• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • Examples
  • File List

E:/E/GEAMP/www/openbiz/openbiz/others/Zend/Mail/Protocol/Imap.php

00001 <?php
00031 class Zend_Mail_Protocol_Imap
00032 {
00036     const TIMEOUT_CONNECTION = 30;
00037 
00042     protected $_socket;
00043 
00048     protected $_tagCount = 0;
00049 
00058     function __construct($host = '', $port = null, $ssl = false)
00059     {
00060         if ($host) {
00061             $this->connect($host, $port, $ssl);
00062         }
00063     }
00064 
00068     public function __destruct()
00069     {
00070         $this->logout();
00071     }
00072 
00082     public function connect($host, $port = null, $ssl = false)
00083     {
00084         if ($ssl == 'SSL') {
00085             $host = 'ssl://' . $host;
00086         }
00087 
00088         if ($port === null) {
00089             $port = $ssl === 'SSL' ? 993 : 143;
00090         }
00091 
00092         $errno  =  0;
00093         $errstr = '';
00094         $this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
00095         if (!$this->_socket) {
00099             require_once 'Zend/Mail/Protocol/Exception.php';
00100             throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr .
00101                                                    ' (errno = ' . $errno . ' )');
00102         }
00103 
00104         if (!$this->_assumedNextLine('* OK')) {
00108             require_once 'Zend/Mail/Protocol/Exception.php';
00109             throw new Zend_Mail_Protocol_Exception('host doesn\'t allow connection');
00110         }
00111 
00112         if ($ssl === 'TLS') {
00113             $result = $this->requestAndResponse('STARTTLS');
00114             $result = $result && stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
00115             if (!$result) {
00119                 require_once 'Zend/Mail/Protocol/Exception.php';
00120                 throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
00121             }
00122         }
00123     }
00124 
00131     protected function _nextLine()
00132     {
00133         $line = @fgets($this->_socket);
00134         if ($line === false) {
00138             require_once 'Zend/Mail/Protocol/Exception.php';
00139             throw new Zend_Mail_Protocol_Exception('cannot read - connection closed?');
00140         }
00141 
00142         return $line;
00143     }
00144 
00153     protected function _assumedNextLine($start)
00154     {
00155         $line = $this->_nextLine();
00156         return strpos($line, $start) === 0;
00157     }
00158 
00166     protected function _nextTaggedLine(&$tag)
00167     {
00168         $line = $this->_nextLine();
00169 
00170         // seperate tag from line
00171         list($tag, $line) = explode(' ', $line, 2);
00172 
00173         return $line;
00174     }
00175 
00183     protected function _decodeLine($line)
00184     {
00185         $tokens = array();
00186         $stack = array();
00187 
00188         /*
00189             We start to decode the response here. The unterstood tokens are:
00190                 literal
00191                 "literal" or also "lit\\er\"al"
00192                 {bytes}<NL>literal
00193                 (literals*)
00194             All tokens are returned in an array. Literals in braces (the last unterstood
00195             token in the list) are returned as an array of tokens. I.e. the following response:
00196                 "foo" baz {3}<NL>bar ("f\\\"oo" bar)
00197             would be returned as:
00198                 array('foo', 'baz', 'bar', array('f\\\"oo', 'bar'));
00199 
00200             // TODO: add handling of '[' and ']' to parser for easier handling of response text
00201         */
00202         //  replace any trailling <NL> including spaces with a single space
00203         $line = rtrim($line) . ' ';
00204         while (($pos = strpos($line, ' ')) !== false) {
00205             $token = substr($line, 0, $pos);
00206             while ($token[0] == '(') {
00207                 array_push($stack, $tokens);
00208                 $tokens = array();
00209                 $token = substr($token, 1);
00210             }
00211             if ($token[0] == '"') {
00212                 if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) {
00213                     $tokens[] = $matches[1];
00214                     $line = substr($line, strlen($matches[0]));
00215                     continue;
00216                 }
00217             }
00218             if ($token[0] == '{') {
00219                 $endPos = strpos($token, '}');
00220                 $chars = substr($token, 1, $endPos - 1);
00221                 if (is_numeric($chars)) {
00222                     $token = '';
00223                     while (strlen($token) < $chars) {
00224                         $token .= $this->_nextLine();
00225                     }
00226                     $line = '';
00227                     if (strlen($token) > $chars) {
00228                         $line = substr($token, $chars);
00229                         $token = substr($token, 0, $chars);
00230                     } else {
00231                         $line .= $this->_nextLine();
00232                     }
00233                     $tokens[] = $token;
00234                     $line = trim($line) . ' ';
00235                     continue;
00236                 }
00237             }
00238             if ($stack && $token[strlen($token) - 1] == ')') {
00239                 // closing braces are not seperated by spaces, so we need to count them
00240                 $braces = strlen($token);
00241                 $token = rtrim($token, ')');
00242                 // only count braces if more than one
00243                 $braces -= strlen($token) + 1;
00244                 // only add if token had more than just closing braces
00245                 if (rtrim($token) != '') {
00246                     $tokens[] = rtrim($token);
00247                 }
00248                 $token = $tokens;
00249                 $tokens = array_pop($stack);
00250                 // special handline if more than one closing brace
00251                 while ($braces-- > 0) {
00252                     $tokens[] = $token;
00253                     $token = $tokens;
00254                     $tokens = array_pop($stack);
00255                 }
00256             }
00257             $tokens[] = $token;
00258             $line = substr($line, $pos + 1);
00259         }
00260 
00261         // maybe the server forgot to send some closing braces
00262         while ($stack) {
00263             $child = $tokens;
00264             $tokens = array_pop($stack);
00265             $tokens[] = $child;
00266         }
00267 
00268         return $tokens;
00269     }
00270 
00283     public function readLine(&$tokens = array(), $wantedTag = '*', $dontParse = false)
00284     {
00285         $line = $this->_nextTaggedLine($tag);
00286         if (!$dontParse) {
00287             $tokens = $this->_decodeLine($line);
00288         } else {
00289             $tokens = $line;
00290         }
00291 
00292         // if tag is wanted tag we might be at the end of a multiline response
00293         return $tag == $wantedTag;
00294     }
00295 
00307     public function readResponse($tag, $dontParse = false)
00308     {
00309         $lines = array();
00310         while (!$this->readLine($tokens, $tag, $dontParse)) {
00311             $lines[] = $tokens;
00312         }
00313 
00314         if ($dontParse) {
00315             // last to chars are still needed for response code
00316             $tokens = array(substr($tokens, 0, 2));
00317         }
00318         // last line has response code
00319         if ($tokens[0] == 'OK') {
00320             return $lines ? $lines : true;
00321         } else if ($tokens[0] == 'NO'){
00322             return false;
00323         }
00324         return null;
00325     }
00326 
00336     public function sendRequest($command, $tokens = array(), &$tag = null)
00337     {
00338         if (!$tag) {
00339             ++$this->_tagCount;
00340             $tag = 'TAG' . $this->_tagCount;
00341         }
00342 
00343         $line = $tag . ' ' . $command;
00344 
00345         foreach ($tokens as $token) {
00346             if (is_array($token)) {
00347                 if (@fputs($this->_socket, $line . ' ' . $token[0] . "\r\n") === false) {
00351                     require_once 'Zend/Mail/Protocol/Exception.php';
00352                     throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
00353                 }
00354                 if (!$this->_assumedNextLine('+ ')) {
00358                     require_once 'Zend/Mail/Protocol/Exception.php';
00359                     throw new Zend_Mail_Protocol_Exception('cannot send literal string');
00360                 }
00361                 $line = $token[1];
00362             } else {
00363                 $line .= ' ' . $token;
00364             }
00365         }
00366 
00367         if (@fputs($this->_socket, $line . "\r\n") === false) {
00371             require_once 'Zend/Mail/Protocol/Exception.php';
00372             throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
00373         }
00374     }
00375 
00385     public function requestAndResponse($command, $tokens = array(), $dontParse = false)
00386     {
00387         $this->sendRequest($command, $tokens, $tag);
00388         $response = $this->readResponse($tag, $dontParse);
00389 
00390         return $response;
00391     }
00392 
00400     public function escapeString($string)
00401     {
00402         if (func_num_args() < 2) {
00403             if (strpos($string, "\n") !== false) {
00404                 return array('{' . strlen($string) . '}', $string);
00405             } else {
00406                 return '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $string) . '"';
00407             }
00408         }
00409         $result = array();
00410         foreach (func_get_args() as $string) {
00411             $result[] = $this->escapeString($string);
00412         }
00413         return $result;
00414     }
00415 
00422     public function escapeList($list)
00423     {
00424         $result = array();
00425         foreach ($list as $k => $v) {
00426             if (!is_array($v)) {
00427 //              $result[] = $this->escapeString($v);
00428                 $result[] = $v;
00429                 continue;
00430             }
00431             $result[] = $this->escapeList($v);
00432         }
00433         return '(' . implode(' ', $result) . ')';
00434     }
00435 
00444     public function login($user, $password)
00445     {
00446         return $this->requestAndResponse('LOGIN', $this->escapeString($user, $password), true);
00447     }
00448 
00454     public function logout()
00455     {
00456         $result = false;
00457         if ($this->_socket) {
00458             try {
00459                 $result = $this->requestAndResponse('LOGOUT', array(), true);
00460             } catch (Zend_Mail_Protocol_Exception $e) {
00461                 // ignoring exception
00462             }
00463             fclose($this->_socket);
00464             $this->_socket = null;
00465         }
00466         return $result;
00467     }
00468 
00469 
00476     public function capability()
00477     {
00478         $response = $this->requestAndResponse('CAPABILITY');
00479 
00480         if (!$response) {
00481             return $response;
00482         }
00483 
00484         $capabilities = array();
00485         foreach ($response as $line) {
00486             $capabilities = array_merge($capabilities, $line);
00487         }
00488         return $capabilities;
00489     }
00490 
00501     public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
00502     {
00503         $this->sendRequest($command, array($this->escapeString($box)), $tag);
00504 
00505         $result = array();
00506         while (!$this->readLine($tokens, $tag)) {
00507             if ($tokens[0] == 'FLAGS') {
00508                 array_shift($tokens);
00509                 $result['flags'] = $tokens;
00510                 continue;
00511             }
00512             switch ($tokens[1]) {
00513                 case 'EXISTS':
00514                 case 'RECENT':
00515                     $result[strtolower($tokens[1])] = $tokens[0];
00516                     break;
00517                 case '[UIDVALIDITY':
00518                     $result['uidvalidity'] = (int)$tokens[2];
00519                     break;
00520                 default:
00521                     // ignore
00522             }
00523         }
00524 
00525         if ($tokens[0] != 'OK') {
00526             return false;
00527         }
00528         return $result;
00529     }
00530 
00538     public function select($box = 'INBOX')
00539     {
00540         return $this->examineOrSelect('SELECT', $box);
00541     }
00542 
00550     public function examine($box = 'INBOX')
00551     {
00552         return $this->examineOrSelect('EXAMINE', $box);
00553     }
00554 
00569     public function fetch($items, $from, $to = null)
00570     {
00571         if (is_array($from)) {
00572             $set = implode(',', $from);
00573         } else if ($to === null) {
00574             $set = (int)$from;
00575         } else if ($to === INF) {
00576             $set = (int)$from . ':*';
00577         } else {
00578             $set = (int)$from . ':' . (int)$to;
00579         }
00580 
00581         $items = (array)$items;
00582         $itemList = $this->escapeList($items);
00583 
00584         $this->sendRequest('FETCH', array($set, $itemList), $tag);
00585 
00586         $result = array();
00587         while (!$this->readLine($tokens, $tag)) {
00588             // ignore other responses
00589             if ($tokens[1] != 'FETCH') {
00590                 continue;
00591             }
00592             // ignore other messages
00593             if ($to === null && !is_array($from) && $tokens[0] != $from) {
00594                 continue;
00595             }
00596             // if we only want one item we return that one directly
00597             if (count($items) == 1) {
00598                 if ($tokens[2][0] == $items[0]) {
00599                     $data = $tokens[2][1];
00600                 } else {
00601                     // maybe the server send an other field we didn't wanted
00602                     $count = count($tokens[2]);
00603                     // we start with 2, because 0 was already checked
00604                     for ($i = 2; $i < $count; $i += 2) {
00605                         if ($tokens[2][$i] != $items[0]) {
00606                             continue;
00607                         }
00608                         $data = $tokens[2][$i + 1];
00609                         break;
00610                     }
00611                 }
00612             } else {
00613                 $data = array();
00614                 while (key($tokens[2]) !== null) {
00615                     $data[current($tokens[2])] = next($tokens[2]);
00616                     next($tokens[2]);
00617                 }
00618             }
00619             // if we want only one message we can ignore everything else and just return
00620             if ($to === null && !is_array($from) && $tokens[0] == $from) {
00621                 // we still need to read all lines
00622                 while (!$this->readLine($tokens, $tag));
00623                 return $data;
00624             }
00625             $result[$tokens[0]] = $data;
00626         }
00627 
00628         if ($to === null && !is_array($from)) {
00632             require_once 'Zend/Mail/Protocol/Exception.php';
00633             throw new Zend_Mail_Protocol_Exception('the single id was not found in response');
00634         }
00635 
00636         return $result;
00637     }
00638 
00649     public function listMailbox($reference = '', $mailbox = '*')
00650     {
00651         $result = array();
00652         $list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
00653         if (!$list || $list === true) {
00654             return $result;
00655         }
00656 
00657         foreach ($list as $item) {
00658             if (count($item) != 4 || $item[0] != 'LIST') {
00659                 continue;
00660             }
00661             $result[$item[3]] = array('delim' => $item[2], 'flags' => $item[1]);
00662         }
00663 
00664         return $result;
00665     }
00666 
00679     public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
00680     {
00681         $item = 'FLAGS';
00682         if ($mode == '+' || $mode == '-') {
00683             $item = $mode . $item;
00684         }
00685         if ($silent) {
00686             $item .= '.SILENT';
00687         }
00688 
00689         $flags = $this->escapeList($flags);
00690         $set = (int)$from;
00691         if ($to != null) {
00692             $set .= ':' . ($to == INF ? '*' : (int)$to);
00693         }
00694 
00695         $result = $this->requestAndResponse('STORE', array($set, $item, $flags), $silent);
00696 
00697         if ($silent) {
00698             return $result ? true : false;
00699         }
00700 
00701         $tokens = $result;
00702         $result = array();
00703         foreach ($tokens as $token) {
00704             if ($token[1] != 'FETCH' || $token[2][0] != 'FLAGS') {
00705                 continue;
00706             }
00707             $result[$token[0]] = $token[2][1];
00708         }
00709 
00710         return $result;
00711     }
00712 
00723     public function append($folder, $message, $flags = null, $date = null)
00724     {
00725         $tokens = array();
00726         $tokens[] = $this->escapeString($folder);
00727         if ($flags !== null) {
00728             $tokens[] = $this->escapeList($flags);
00729         }
00730         if ($date !== null) {
00731             $tokens[] = $this->escapeString($date);
00732         }
00733         $tokens[] = $this->escapeString($message);
00734 
00735         return $this->requestAndResponse('APPEND', $tokens, true);
00736     }
00737 
00747     public function copy($folder, $from, $to = null)
00748     {
00749         $set = (int)$from;
00750         if ($to != null) {
00751             $set .= ':' . ($to == INF ? '*' : (int)$to);
00752         }
00753 
00754         return $this->requestAndResponse('COPY', array($set, $this->escapeString($folder)), true);
00755     }
00756 
00763     public function create($folder)
00764     {
00765         return $this->requestAndResponse('CREATE', array($this->escapeString($folder)), true);
00766     }
00767 
00775     public function rename($old, $new)
00776     {
00777         return $this->requestAndResponse('RENAME', $this->escapeString($old, $new), true);
00778     }
00779 
00786     public function delete($folder)
00787     {
00788         return $this->requestAndResponse('DELETE', array($this->escapeString($folder)), true);
00789     }
00790 
00796     public function expunge()
00797     {
00798         // TODO: parse response?
00799         return $this->requestAndResponse('EXPUNGE');
00800     }
00801 
00807     public function noop()
00808     {
00809         // TODO: parse response
00810         return $this->requestAndResponse('NOOP');
00811     }
00812 
00822     public function search(array $params)
00823     {
00824         $response = $this->requestAndResponse('SEARCH', $params);
00825         if (!$response) {
00826             return $response;
00827         }
00828 
00829         foreach ($response as $ids) {
00830             if ($ids[0] == 'SEARCH') {
00831                 array_shift($ids);
00832                 return $ids;
00833             }
00834         }
00835         return array();
00836     }
00837 
00838 }

Generated on Thu Apr 19 2012 17:01:18 for openbiz by  doxygen 1.7.2