Changeset c2c820c in github


Ignore:
Timestamp:
Dec 9, 2010 9:56:06 AM (2 years ago)
Author:
alecpl <alec@…>
Branches:
master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
Children:
3ee5a72
Parents:
ad399a9
Message:
  • CS fixes
File:
1 edited

Legend:

Unmodified
Added
Removed
  • program/include/rcube_imap_generic.php

    rad399a9 rc2c820c  
    11<?php 
    22 
    3 /* 
     3/** 
    44 +-----------------------------------------------------------------------+ 
    55 | program/include/rcube_imap_generic.php                                | 
     
    3030 * Struct representing an e-mail message header 
    3131 * 
    32  * @package    Mail 
    33  * @author     Aleksander Machniak <alec@alec.pl> 
     32 * @package Mail 
     33 * @author  Aleksander Machniak <alec@alec.pl> 
    3434 */ 
    3535class rcube_mail_header 
    3636{ 
    37         public $id; 
    38         public $uid; 
    39         public $subject; 
    40         public $from; 
    41         public $to; 
    42         public $cc; 
    43         public $replyto; 
    44         public $in_reply_to; 
    45         public $date; 
    46         public $messageID; 
    47         public $size; 
    48         public $encoding; 
    49         public $charset; 
    50         public $ctype; 
    51         public $flags; 
    52         public $timestamp; 
    53         public $body_structure; 
    54         public $internaldate; 
    55         public $references; 
    56         public $priority; 
    57         public $mdn_to; 
    58         public $mdn_sent = false; 
    59         public $is_draft = false; 
    60         public $seen = false; 
    61         public $deleted = false; 
    62         public $recent = false; 
    63         public $answered = false; 
    64         public $forwarded = false; 
    65         public $junk = false; 
    66         public $flagged = false; 
    67         public $has_children = false; 
    68         public $depth = 0; 
    69         public $unread_children = 0; 
    70         public $others = array(); 
     37    public $id; 
     38    public $uid; 
     39    public $subject; 
     40    public $from; 
     41    public $to; 
     42    public $cc; 
     43    public $replyto; 
     44    public $in_reply_to; 
     45    public $date; 
     46    public $messageID; 
     47    public $size; 
     48    public $encoding; 
     49    public $charset; 
     50    public $ctype; 
     51    public $flags; 
     52    public $timestamp; 
     53    public $body_structure; 
     54    public $internaldate; 
     55    public $references; 
     56    public $priority; 
     57    public $mdn_to; 
     58    public $mdn_sent = false; 
     59    public $is_draft = false; 
     60    public $seen = false; 
     61    public $deleted = false; 
     62    public $recent = false; 
     63    public $answered = false; 
     64    public $forwarded = false; 
     65    public $junk = false; 
     66    public $flagged = false; 
     67    public $has_children = false; 
     68    public $depth = 0; 
     69    public $unread_children = 0; 
     70    public $others = array(); 
    7171} 
    7272 
     
    7979 * PHP based wrapper class to connect to an IMAP server 
    8080 * 
    81  * @package    Mail 
    82  * @author     Aleksander Machniak <alec@alec.pl> 
     81 * @package Mail 
     82 * @author  Aleksander Machniak <alec@alec.pl> 
    8383 */ 
    8484class rcube_imap_generic 
     
    102102 
    103103    private $selected; 
    104         private $fp; 
    105         private $host; 
    106         private $logged = false; 
    107         private $capability = array(); 
    108         private $capability_readed = false; 
     104    private $fp; 
     105    private $host; 
     106    private $logged = false; 
     107    private $capability = array(); 
     108    private $capability_readed = false; 
    109109    private $prefs; 
    110110    private $cmd_tag; 
     
    143143            return false; 
    144144 
    145                 if (!empty($this->prefs['debug_mode'])) { 
    146                 write_log('imap', 'C: '. rtrim($string)); 
    147             } 
     145        if (!empty($this->prefs['debug_mode'])) { 
     146            write_log('imap', 'C: '. rtrim($string)); 
     147        } 
    148148 
    149149        $res = fwrite($this->fp, $string . ($endln ? "\r\n" : '')); 
    150150 
    151                 if ($res === false) { 
    152                 @fclose($this->fp); 
    153                 $this->fp = null; 
    154                 } 
     151        if ($res === false) { 
     152            @fclose($this->fp); 
     153            $this->fp = null; 
     154        } 
    155155 
    156156        return $res; 
     
    171171            return false; 
    172172 
    173             if ($endln) 
    174                     $string .= "\r\n"; 
    175  
    176             $res = 0; 
    177             if ($parts = preg_split('/(\{[0-9]+\}\r\n)/m', $string, -1, PREG_SPLIT_DELIM_CAPTURE)) { 
    178                     for ($i=0, $cnt=count($parts); $i<$cnt; $i++) { 
    179                             if (preg_match('/^\{[0-9]+\}\r\n$/', $parts[$i+1])) { 
     173        if ($endln) 
     174            $string .= "\r\n"; 
     175 
     176        $res = 0; 
     177        if ($parts = preg_split('/(\{[0-9]+\}\r\n)/m', $string, -1, PREG_SPLIT_DELIM_CAPTURE)) { 
     178            for ($i=0, $cnt=count($parts); $i<$cnt; $i++) { 
     179                if (preg_match('/^\{[0-9]+\}\r\n$/', $parts[$i+1])) { 
    180180                    // LITERAL+ support 
    181181                    if ($this->prefs['literal+']) 
    182182                        $parts[$i+1] = preg_replace('/([0-9]+)/', '\\1+', $parts[$i+1]); 
    183183 
    184                                     $bytes = $this->putLine($parts[$i].$parts[$i+1], false); 
     184                    $bytes = $this->putLine($parts[$i].$parts[$i+1], false); 
    185185                    if ($bytes === false) 
    186186                        return false; 
     
    189189                    // don't wait if server supports LITERAL+ capability 
    190190                    if (!$this->prefs['literal+']) { 
    191                                         $line = $this->readLine(1000); 
    192                                         // handle error in command 
    193                                         if ($line[0] != '+') 
    194                                                 return false; 
    195                                     } 
     191                        $line = $this->readLine(1000); 
     192                        // handle error in command 
     193                        if ($line[0] != '+') 
     194                            return false; 
     195                    } 
    196196                    $i++; 
    197                             } 
    198                             else { 
    199                                     $bytes = $this->putLine($parts[$i], false); 
     197                } 
     198                else { 
     199                    $bytes = $this->putLine($parts[$i], false); 
    200200                    if ($bytes === false) 
    201201                        return false; 
    202202                    $res += $bytes; 
    203203                } 
    204                     } 
    205             } 
    206  
    207             return $res; 
     204            } 
     205        } 
     206 
     207        return $res; 
    208208    } 
    209209 
    210210    function readLine($size=1024) 
    211211    { 
    212                 $line = ''; 
    213  
    214             if (!$this->fp) { 
    215                 return NULL; 
    216             } 
    217  
    218             if (!$size) { 
    219                     $size = 1024; 
    220             } 
    221  
    222             do { 
    223                     if (feof($this->fp)) { 
    224                             return $line ? $line : NULL; 
    225                     } 
    226  
    227                 $buffer = fgets($this->fp, $size); 
    228  
    229                 if ($buffer === false) { 
    230                 @fclose($this->fp); 
    231                 $this->fp = null; 
    232                         break; 
    233                 } 
    234                     if (!empty($this->prefs['debug_mode'])) { 
    235                             write_log('imap', 'S: '. rtrim($buffer)); 
    236                 } 
     212        $line = ''; 
     213 
     214        if (!$this->fp) { 
     215            return NULL; 
     216        } 
     217 
     218        if (!$size) { 
     219            $size = 1024; 
     220        } 
     221 
     222        do { 
     223            if (feof($this->fp)) { 
     224                return $line ? $line : NULL; 
     225            } 
     226 
     227            $buffer = fgets($this->fp, $size); 
     228 
     229            if ($buffer === false) { 
     230                @fclose($this->fp); 
     231                $this->fp = null; 
     232                break; 
     233            } 
     234            if (!empty($this->prefs['debug_mode'])) { 
     235                write_log('imap', 'S: '. rtrim($buffer)); 
     236            } 
    237237            $line .= $buffer; 
    238             } while ($buffer[strlen($buffer)-1] != "\n"); 
    239  
    240             return $line; 
     238        } while ($buffer[strlen($buffer)-1] != "\n"); 
     239 
     240        return $line; 
    241241    } 
    242242 
    243243    function multLine($line, $escape=false) 
    244244    { 
    245             $line = rtrim($line); 
    246             if (preg_match('/\{[0-9]+\}$/', $line)) { 
    247                     $out = ''; 
    248  
    249                     preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a); 
    250                     $bytes = $a[2][0]; 
    251                     while (strlen($out) < $bytes) { 
    252                             $line = $this->readBytes($bytes); 
    253                             if ($line === NULL) 
    254                                     break; 
    255                             $out .= $line; 
    256                     } 
    257  
    258                     $line = $a[1][0] . ($escape ? $this->escape($out) : $out); 
    259             } 
     245        $line = rtrim($line); 
     246        if (preg_match('/\{[0-9]+\}$/', $line)) { 
     247            $out = ''; 
     248 
     249            preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a); 
     250            $bytes = $a[2][0]; 
     251            while (strlen($out) < $bytes) { 
     252                $line = $this->readBytes($bytes); 
     253                if ($line === NULL) 
     254                    break; 
     255                $out .= $line; 
     256            } 
     257 
     258            $line = $a[1][0] . ($escape ? $this->escape($out) : $out); 
     259        } 
    260260 
    261261        return $line; 
     
    264264    function readBytes($bytes) 
    265265    { 
    266             $data = ''; 
    267             $len  = 0; 
    268             while ($len < $bytes && !feof($this->fp)) 
    269             { 
    270                     $d = fread($this->fp, $bytes-$len); 
    271                     if (!empty($this->prefs['debug_mode'])) { 
    272                             write_log('imap', 'S: '. $d); 
     266        $data = ''; 
     267        $len  = 0; 
     268        while ($len < $bytes && !feof($this->fp)) 
     269        { 
     270            $d = fread($this->fp, $bytes-$len); 
     271            if (!empty($this->prefs['debug_mode'])) { 
     272                write_log('imap', 'S: '. $d); 
    273273            } 
    274274            $data .= $d; 
    275                     $data_len = strlen($data); 
    276                     if ($len == $data_len) { 
    277                     break; // nothing was read -> exit to avoid apache lockups 
    278                 } 
    279                 $len = $data_len; 
    280             } 
    281  
    282             return $data; 
     275            $data_len = strlen($data); 
     276            if ($len == $data_len) { 
     277                break; // nothing was read -> exit to avoid apache lockups 
     278            } 
     279            $len = $data_len; 
     280        } 
     281 
     282        return $data; 
    283283    } 
    284284 
    285285    function readReply(&$untagged=null) 
    286286    { 
    287             do { 
    288                     $line = trim($this->readLine(1024)); 
     287        do { 
     288            $line = trim($this->readLine(1024)); 
    289289            // store untagged response lines 
    290                     if ($line[0] == '*') 
     290            if ($line[0] == '*') 
    291291                $untagged[] = $line; 
    292             } while ($line[0] == '*'); 
     292        } while ($line[0] == '*'); 
    293293 
    294294        if ($untagged) 
    295295            $untagged = join("\n", $untagged); 
    296296 
    297             return $line; 
     297        return $line; 
    298298    } 
    299299 
    300300    function parseResult($string, $err_prefix='') 
    301301    { 
    302             if (preg_match('/^[a-z0-9*]+ (OK|NO|BAD|BYE)(.*)$/i', trim($string), $matches)) { 
    303                     $res = strtoupper($matches[1]); 
     302        if (preg_match('/^[a-z0-9*]+ (OK|NO|BAD|BYE)(.*)$/i', trim($string), $matches)) { 
     303            $res = strtoupper($matches[1]); 
    304304            $str = trim($matches[2]); 
    305305 
    306                     if ($res == 'OK') { 
    307                             $this->errornum = self::ERROR_OK; 
    308                     } else if ($res == 'NO') { 
     306            if ($res == 'OK') { 
     307                $this->errornum = self::ERROR_OK; 
     308            } else if ($res == 'NO') { 
    309309                $this->errornum = self::ERROR_NO; 
    310                     } else if ($res == 'BAD') { 
    311                             $this->errornum = self::ERROR_BAD; 
    312                     } else if ($res == 'BYE') { 
     310            } else if ($res == 'BAD') { 
     311                $this->errornum = self::ERROR_BAD; 
     312            } else if ($res == 'BYE') { 
    313313                @fclose($this->fp); 
    314314                $this->fp = null; 
    315                             $this->errornum = self::ERROR_BYE; 
    316                     } 
     315                $this->errornum = self::ERROR_BYE; 
     316            } 
    317317 
    318318            if ($str) { 
     
    333333            } 
    334334 
    335                 return $this->errornum; 
    336             } 
    337             return self::ERROR_UNKNOWN; 
     335            return $this->errornum; 
     336        } 
     337        return self::ERROR_UNKNOWN; 
    338338    } 
    339339 
     
    347347    function startsWith($string, $match, $error=false, $nonempty=false) 
    348348    { 
    349             $len = strlen($match); 
    350             if ($len == 0) { 
    351                     return false; 
    352             } 
     349        $len = strlen($match); 
     350        if ($len == 0) { 
     351            return false; 
     352        } 
    353353        if (!$this->fp) { 
    354354            return true; 
    355355        } 
    356             if (strncmp($string, $match, $len) == 0) { 
    357                     return true; 
    358             } 
    359             if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { 
     356        if (strncmp($string, $match, $len) == 0) { 
     357            return true; 
     358        } 
     359        if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { 
    360360            if (strtoupper($m[1]) == 'BYE') { 
    361361                @fclose($this->fp); 
    362362                $this->fp = null; 
    363363            } 
    364                     return true; 
    365             } 
     364            return true; 
     365        } 
    366366        if ($nonempty && !strlen($string)) { 
    367367            return true; 
    368368        } 
    369             return false; 
     369        return false; 
    370370    } 
    371371 
    372372    function getCapability($name) 
    373373    { 
    374             if (in_array($name, $this->capability)) { 
    375                     return true; 
    376             } 
    377             else if ($this->capability_readed) { 
    378                     return false; 
    379             } 
    380  
    381             // get capabilities (only once) because initial 
    382             // optional CAPABILITY response may differ 
     374        if (in_array($name, $this->capability)) { 
     375            return true; 
     376        } 
     377        else if ($this->capability_readed) { 
     378            return false; 
     379        } 
     380 
     381        // get capabilities (only once) because initial 
     382        // optional CAPABILITY response may differ 
    383383        $result = $this->execute('CAPABILITY'); 
    384384 
     
    387387        } 
    388388 
    389             $this->capability_readed = true; 
    390  
    391             if (in_array($name, $this->capability)) { 
    392                     return true; 
    393             } 
    394  
    395             return false; 
     389        $this->capability_readed = true; 
     390 
     391        if (in_array($name, $this->capability)) { 
     392            return true; 
     393        } 
     394 
     395        return false; 
    396396    } 
    397397 
    398398    function clearCapability() 
    399399    { 
    400             $this->capability = array(); 
    401             $this->capability_readed = false; 
     400        $this->capability = array(); 
     401        $this->capability_readed = false; 
    402402    } 
    403403 
     
    417417                $this->setError(self::ERROR_BYE, 
    418418                    "The Auth_SASL package is required for DIGEST-MD5 authentication"); 
    419                             return self::ERROR_BAD; 
    420             } 
    421  
    422                     $this->putLine($this->nextTag() . " AUTHENTICATE $type"); 
    423                     $line = trim($this->readReply()); 
    424  
    425                     if ($line[0] == '+') { 
    426                             $challenge = substr($line, 2); 
     419                return self::ERROR_BAD; 
     420            } 
     421 
     422            $this->putLine($this->nextTag() . " AUTHENTICATE $type"); 
     423            $line = trim($this->readReply()); 
     424 
     425            if ($line[0] == '+') { 
     426                $challenge = substr($line, 2); 
    427427            } 
    428428            else { 
    429429                return $this->parseResult($line); 
    430                     } 
     430            } 
    431431 
    432432            if ($type == 'CRAM-MD5') { 
     
    474474 
    475475                if ($line[0] == '+') { 
    476                                 $challenge = substr($line, 2); 
     476                    $challenge = substr($line, 2); 
    477477                } 
    478478                else { 
     
    512512            } 
    513513            else { 
    514                     $this->putLine($this->nextTag() . " AUTHENTICATE PLAIN"); 
    515                     $line = trim($this->readReply()); 
    516  
    517                         if ($line[0] != '+') { 
    518                             return $this->parseResult($line); 
    519                     } 
     514                $this->putLine($this->nextTag() . " AUTHENTICATE PLAIN"); 
     515                $line = trim($this->readReply()); 
     516 
     517                if ($line[0] != '+') { 
     518                    return $this->parseResult($line); 
     519                } 
    520520 
    521521                // send result, get reply and process it 
     
    527527 
    528528        if ($result == self::ERROR_OK) { 
    529             // optional CAPABILITY response 
    530                 if ($line && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { 
    531                         $this->parseCapability($matches[1], true); 
    532                 } 
     529            // optional CAPABILITY response 
     530            if ($line && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { 
     531                $this->parseCapability($matches[1], true); 
     532            } 
    533533            return $this->fp; 
    534534        } 
     
    554554 
    555555        // re-set capabilities list if untagged CAPABILITY response provided 
    556             if (preg_match('/\* CAPABILITY (.+)/i', $response, $matches)) { 
    557                     $this->parseCapability($matches[1], true); 
    558             } 
     556        if (preg_match('/\* CAPABILITY (.+)/i', $response, $matches)) { 
     557            $this->parseCapability($matches[1], true); 
     558        } 
    559559 
    560560        if ($code == self::ERROR_OK) { 
     
    572572    function getHierarchyDelimiter() 
    573573    { 
    574             if ($this->prefs['delimiter']) { 
    575                 return $this->prefs['delimiter']; 
    576             } 
    577  
    578             // try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8) 
    579             list($code, $response) = $this->execute('LIST', 
    580                 array($this->escape(''), $this->escape(''))); 
     574        if ($this->prefs['delimiter']) { 
     575            return $this->prefs['delimiter']; 
     576        } 
     577 
     578        // try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8) 
     579        list($code, $response) = $this->execute('LIST', 
     580            array($this->escape(''), $this->escape(''))); 
    581581 
    582582        if ($code == self::ERROR_OK) { 
     
    584584            $delimiter = $args[3]; 
    585585 
    586                 if (strlen($delimiter) > 0) { 
    587                     return ($this->prefs['delimiter'] = $delimiter); 
    588                 } 
     586            if (strlen($delimiter) > 0) { 
     587                return ($this->prefs['delimiter'] = $delimiter); 
     588            } 
    589589        } 
    590590 
     
    604604 
    605605        if (!$this->getCapability('NAMESPACE')) { 
    606                 return self::ERROR_BAD; 
    607             } 
    608  
    609             list($code, $response) = $this->execute('NAMESPACE'); 
    610  
    611                 if ($code == self::ERROR_OK && preg_match('/^\* NAMESPACE /', $response)) { 
    612                 $data = $this->tokenizeResponse(substr($response, 11)); 
    613                 } 
    614  
    615             if (!is_array($data)) { 
    616                 return $code; 
    617             } 
     606            return self::ERROR_BAD; 
     607        } 
     608 
     609        list($code, $response) = $this->execute('NAMESPACE'); 
     610 
     611        if ($code == self::ERROR_OK && preg_match('/^\* NAMESPACE /', $response)) { 
     612            $data = $this->tokenizeResponse(substr($response, 11)); 
     613        } 
     614 
     615        if (!is_array($data)) { 
     616            return $code; 
     617        } 
    618618 
    619619        $this->prefs['namespace'] = array( 
     
    628628    function connect($host, $user, $password, $options=null) 
    629629    { 
    630             // set options 
    631             if (is_array($options)) { 
     630        // set options 
     631        if (is_array($options)) { 
    632632            $this->prefs = $options; 
    633633        } 
     
    635635        if (!empty($this->prefs['auth_method'])) { 
    636636            $auth_method = strtoupper($this->prefs['auth_method']); 
    637             } else { 
    638                 $auth_method = 'CHECK'; 
    639         } 
    640  
    641             $result = false; 
    642  
    643             // initialize connection 
    644             $this->error    = ''; 
    645             $this->errornum = self::ERROR_OK; 
    646             $this->selected = ''; 
    647             $this->user     = $user; 
    648             $this->host     = $host; 
     637        } else { 
     638            $auth_method = 'CHECK'; 
     639        } 
     640 
     641        $result = false; 
     642 
     643        // initialize connection 
     644        $this->error    = ''; 
     645        $this->errornum = self::ERROR_OK; 
     646        $this->selected = ''; 
     647        $this->user     = $user; 
     648        $this->host     = $host; 
    649649        $this->logged   = false; 
    650650 
    651             // check input 
    652             if (empty($host)) { 
    653                     $this->setError(self::ERROR_BAD, "Empty host"); 
    654                     return false; 
    655             } 
     651        // check input 
     652        if (empty($host)) { 
     653            $this->setError(self::ERROR_BAD, "Empty host"); 
     654            return false; 
     655        } 
    656656        if (empty($user)) { 
    657                 $this->setError(self::ERROR_NO, "Empty user"); 
    658                 return false; 
    659             } 
    660             if (empty($password)) { 
    661                 $this->setError(self::ERROR_NO, "Empty password"); 
    662                     return false; 
    663             } 
    664  
    665             if (!$this->prefs['port']) { 
    666                     $this->prefs['port'] = 143; 
    667             } 
    668             // check for SSL 
    669             if ($this->prefs['ssl_mode'] && $this->prefs['ssl_mode'] != 'tls') { 
    670                     $host = $this->prefs['ssl_mode'] . '://' . $host; 
    671             } 
     657            $this->setError(self::ERROR_NO, "Empty user"); 
     658            return false; 
     659        } 
     660        if (empty($password)) { 
     661            $this->setError(self::ERROR_NO, "Empty password"); 
     662            return false; 
     663        } 
     664 
     665        if (!$this->prefs['port']) { 
     666            $this->prefs['port'] = 143; 
     667        } 
     668        // check for SSL 
     669        if ($this->prefs['ssl_mode'] && $this->prefs['ssl_mode'] != 'tls') { 
     670            $host = $this->prefs['ssl_mode'] . '://' . $host; 
     671        } 
    672672 
    673673        // Connect 
    674674        if ($this->prefs['timeout'] > 0) 
    675                 $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); 
    676             else 
    677                 $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr); 
    678  
    679             if (!$this->fp) { 
    680                 $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr)); 
    681                     return false; 
    682             } 
     675            $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); 
     676        else 
     677            $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr); 
     678 
     679        if (!$this->fp) { 
     680            $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr)); 
     681            return false; 
     682        } 
    683683 
    684684        if ($this->prefs['timeout'] > 0) 
    685                 stream_set_timeout($this->fp, $this->prefs['timeout']); 
    686  
    687             $line = trim(fgets($this->fp, 8192)); 
    688  
    689             if ($this->prefs['debug_mode'] && $line) { 
    690                     write_log('imap', 'S: '. $line); 
    691         } 
    692  
    693             // Connected to wrong port or connection error? 
    694             if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) { 
    695                     if ($line) 
    696                             $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line); 
    697                     else 
    698                             $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']); 
    699  
    700                 $this->setError(self::ERROR_BAD, $error); 
     685            stream_set_timeout($this->fp, $this->prefs['timeout']); 
     686 
     687        $line = trim(fgets($this->fp, 8192)); 
     688 
     689        if ($this->prefs['debug_mode'] && $line) { 
     690            write_log('imap', 'S: '. $line); 
     691        } 
     692 
     693        // Connected to wrong port or connection error? 
     694        if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) { 
     695            if ($line) 
     696                $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line); 
     697            else 
     698                $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']); 
     699 
     700            $this->setError(self::ERROR_BAD, $error); 
    701701            $this->closeConnection(); 
    702                 return false; 
    703             } 
    704  
    705             // RFC3501 [7.1] optional CAPABILITY response 
    706             if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { 
    707                     $this->parseCapability($matches[1], true); 
    708             } 
    709  
    710             // TLS connection 
    711             if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) { 
    712                 if (version_compare(PHP_VERSION, '5.1.0', '>=')) { 
    713                 $res = $this->execute('STARTTLS'); 
     702            return false; 
     703        } 
     704 
     705        // RFC3501 [7.1] optional CAPABILITY response 
     706        if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { 
     707            $this->parseCapability($matches[1], true); 
     708        } 
     709 
     710        // TLS connection 
     711        if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) { 
     712            if (version_compare(PHP_VERSION, '5.1.0', '>=')) { 
     713                $res = $this->execute('STARTTLS'); 
    714714 
    715715                if ($res[0] != self::ERROR_OK) { 
     
    718718                } 
    719719 
    720                             if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { 
    721                                     $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); 
     720                if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { 
     721                    $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); 
    722722                    $this->closeConnection(); 
    723                                     return false; 
    724                             } 
    725  
    726                             // Now we're secure, capabilities need to be reread 
    727                             $this->clearCapability(); 
    728                 } 
    729             } 
    730  
    731             $auth_methods = array(); 
     723                    return false; 
     724                } 
     725 
     726                // Now we're secure, capabilities need to be reread 
     727                $this->clearCapability(); 
     728            } 
     729        } 
     730 
     731        $auth_methods = array(); 
    732732        $result       = null; 
    733733 
    734             // check for supported auth methods 
    735             if ($auth_method == 'CHECK') { 
    736                     if ($this->getCapability('AUTH=DIGEST-MD5')) { 
    737                             $auth_methods[] = 'DIGEST-MD5'; 
    738                     } 
    739                     if ($this->getCapability('AUTH=CRAM-MD5') || $this->getCapability('AUTH=CRAM_MD5')) { 
    740                             $auth_methods[] = 'CRAM-MD5'; 
    741                     } 
    742                     if ($this->getCapability('AUTH=PLAIN')) { 
    743                             $auth_methods[] = 'PLAIN'; 
    744                     } 
     734        // check for supported auth methods 
     735        if ($auth_method == 'CHECK') { 
     736            if ($this->getCapability('AUTH=DIGEST-MD5')) { 
     737                $auth_methods[] = 'DIGEST-MD5'; 
     738            } 
     739            if ($this->getCapability('AUTH=CRAM-MD5') || $this->getCapability('AUTH=CRAM_MD5')) { 
     740                $auth_methods[] = 'CRAM-MD5'; 
     741            } 
     742            if ($this->getCapability('AUTH=PLAIN')) { 
     743                $auth_methods[] = 'PLAIN'; 
     744            } 
    745745            // RFC 2595 (LOGINDISABLED) LOGIN disabled when connection is not secure 
    746                     if (!$this->getCapability('LOGINDISABLED')) { 
    747                             $auth_methods[] = 'LOGIN'; 
    748                     } 
    749             } 
     746            if (!$this->getCapability('LOGINDISABLED')) { 
     747                $auth_methods[] = 'LOGIN'; 
     748            } 
     749        } 
    750750        else { 
    751751            // Prevent from sending credentials in plain text when connection is not secure 
    752                     if ($auth_method == 'LOGIN' && $this->getCapability('LOGINDISABLED')) { 
    753                             $this->setError(self::ERROR_BAD, "Login disabled by IMAP server"); 
     752            if ($auth_method == 'LOGIN' && $this->getCapability('LOGINDISABLED')) { 
     753                $this->setError(self::ERROR_BAD, "Login disabled by IMAP server"); 
    754754                $this->closeConnection(); 
    755                             return false; 
     755                return false; 
    756756            } 
    757757            // replace AUTH with CRAM-MD5 for backward compat. 
     
    767767            case 'DIGEST-MD5': 
    768768            case 'CRAM-MD5': 
    769                 case 'PLAIN': 
    770                             $result = $this->authenticate($user, $password, $method); 
    771                         break; 
     769            case 'PLAIN': 
     770                $result = $this->authenticate($user, $password, $method); 
     771                break; 
    772772            case 'LOGIN': 
    773                 $result = $this->login($user, $password); 
     773                $result = $this->login($user, $password); 
    774774                break; 
    775775            default: 
     
    777777            } 
    778778 
    779                     if (is_resource($result)) { 
    780                             break; 
    781                     } 
    782             } 
     779            if (is_resource($result)) { 
     780                break; 
     781            } 
     782        } 
    783783 
    784784        // Connected and authenticated 
    785             if (is_resource($result)) { 
     785        if (is_resource($result)) { 
    786786            if ($this->prefs['force_caps']) { 
    787                             $this->clearCapability(); 
     787                $this->clearCapability(); 
    788788            } 
    789789            $this->logged = true; 
    790790 
    791                     return true; 
     791            return true; 
    792792        } 
    793793 
     
    799799    function connected() 
    800800    { 
    801                 return ($this->fp && $this->logged) ? true : false; 
     801        return ($this->fp && $this->logged) ? true : false; 
    802802    } 
    803803 
    804804    function closeConnection() 
    805805    { 
    806             if ($this->putLine($this->nextTag() . ' LOGOUT')) { 
    807             $this->readReply(); 
    808         } 
    809  
    810                 @fclose($this->fp); 
    811                 $this->fp = false; 
     806        if ($this->putLine($this->nextTag() . ' LOGOUT')) { 
     807            $this->readReply(); 
     808        } 
     809 
     810        @fclose($this->fp); 
     811        $this->fp = false; 
    812812    } 
    813813 
     
    822822    function select($mailbox) 
    823823    { 
    824             if (!strlen($mailbox)) { 
    825                     return false; 
    826             } 
    827  
    828             if ($this->selected == $mailbox) { 
    829                     return true; 
    830             } 
     824        if (!strlen($mailbox)) { 
     825            return false; 
     826        } 
     827 
     828        if ($this->selected == $mailbox) { 
     829            return true; 
     830        } 
    831831/* 
    832832    Temporary commented out because Courier returns \Noselect for INBOX 
     
    844844            $response = explode("\r\n", $response); 
    845845            foreach ($response as $line) { 
    846                         if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT)$/i', $line, $m)) { 
    847                             $this->data[strtoupper($m[2])] = (int) $m[1]; 
    848                         } 
    849                             else if (preg_match('/^\* OK \[(UIDNEXT|UIDVALIDITY|UNSEEN) ([0-9]+)\]/i', $line, $match)) { 
    850                                 $this->data[strtoupper($match[1])] = (int) $match[2]; 
    851                             } 
    852                             else if (preg_match('/^\* OK \[PERMANENTFLAGS \(([^\)]+)\)\]/iU', $line, $match)) { 
    853                                 $this->data['PERMANENTFLAGS'] = explode(' ', $match[1]); 
    854                             } 
     846                if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT)$/i', $line, $m)) { 
     847                    $this->data[strtoupper($m[2])] = (int) $m[1]; 
     848                } 
     849                else if (preg_match('/^\* OK \[(UIDNEXT|UIDVALIDITY|UNSEEN) ([0-9]+)\]/i', $line, $match)) { 
     850                    $this->data[strtoupper($match[1])] = (int) $match[2]; 
     851                } 
     852                else if (preg_match('/^\* OK \[PERMANENTFLAGS \(([^\)]+)\)\]/iU', $line, $match)) { 
     853                    $this->data['PERMANENTFLAGS'] = explode(' ', $match[1]); 
     854                } 
    855855            } 
    856856 
    857857            $this->data['READ-WRITE'] = $this->resultcode != 'READ-ONLY'; 
    858858 
    859                     $this->selected = $mailbox; 
    860                         return true; 
    861                 } 
     859            $this->selected = $mailbox; 
     860            return true; 
     861        } 
    862862 
    863863        return false; 
     
    878878    function status($mailbox, $items=array()) 
    879879    { 
    880             if (!strlen($mailbox)) { 
    881                     return false; 
    882             } 
     880        if (!strlen($mailbox)) { 
     881            return false; 
     882        } 
    883883 
    884884        if (!in_array('MESSAGES', $items)) { 
     
    904904            $this->data['STATUS:'.$mailbox] = $result; 
    905905 
    906                         return $result; 
    907                 } 
     906            return $result; 
     907        } 
    908908 
    909909        return false; 
     
    921921    function expunge($mailbox, $messages=NULL) 
    922922    { 
    923             if (!$this->select($mailbox)) { 
     923        if (!$this->select($mailbox)) { 
    924924            return false; 
    925925        } 
     
    933933        unset($this->data['STATUS:'.$mailbox]); 
    934934 
    935                 if ($messages) 
    936                         $result = $this->execute('UID EXPUNGE', array($messages), self::COMMAND_NORESPONSE); 
    937                 else 
    938                         $result = $this->execute('EXPUNGE', null, self::COMMAND_NORESPONSE); 
    939  
    940                 if ($result == self::ERROR_OK) { 
    941                         $this->selected = ''; // state has changed, need to reselect 
    942                         return true; 
    943                 } 
    944  
    945             return false; 
     935        if ($messages) 
     936            $result = $this->execute('UID EXPUNGE', array($messages), self::COMMAND_NORESPONSE); 
     937        else 
     938            $result = $this->execute('EXPUNGE', null, self::COMMAND_NORESPONSE); 
     939 
     940        if ($result == self::ERROR_OK) { 
     941            $this->selected = ''; // state has changed, need to reselect 
     942            return true; 
     943        } 
     944 
     945        return false; 
    946946    } 
    947947 
     
    962962        } 
    963963 
    964             return false; 
     964        return false; 
    965965    } 
    966966 
     
    975975    function subscribe($mailbox) 
    976976    { 
    977             $result = $this->execute('SUBSCRIBE', array($this->escape($mailbox)), 
    978                 self::COMMAND_NORESPONSE); 
    979  
    980             return ($result == self::ERROR_OK); 
     977        $result = $this->execute('SUBSCRIBE', array($this->escape($mailbox)), 
     978            self::COMMAND_NORESPONSE); 
     979 
     980        return ($result == self::ERROR_OK); 
    981981    } 
    982982 
     
    991991    function unsubscribe($mailbox) 
    992992    { 
    993             $result = $this->execute('UNSUBSCRIBE', array($this->escape($mailbox)), 
    994                 self::COMMAND_NORESPONSE); 
    995  
    996             return ($result == self::ERROR_OK); 
     993        $result = $this->execute('UNSUBSCRIBE', array($this->escape($mailbox)), 
     994            self::COMMAND_NORESPONSE); 
     995 
     996        return ($result == self::ERROR_OK); 
    997997    } 
    998998 
     
    10081008    { 
    10091009        $result = $this->execute('DELETE', array($this->escape($mailbox)), 
    1010                 self::COMMAND_NORESPONSE); 
    1011  
    1012             return ($result == self::ERROR_OK); 
     1010            self::COMMAND_NORESPONSE); 
     1011 
     1012        return ($result == self::ERROR_OK); 
    10131013    } 
    10141014 
     
    10231023    function clearFolder($mailbox) 
    10241024    { 
    1025             $num_in_trash = $this->countMessages($mailbox); 
    1026             if ($num_in_trash > 0) { 
    1027                     $res = $this->delete($mailbox, '1:*'); 
    1028             } 
     1025        $num_in_trash = $this->countMessages($mailbox); 
     1026        if ($num_in_trash > 0) { 
     1027            $res = $this->delete($mailbox, '1:*'); 
     1028        } 
    10291029 
    10301030        if ($res) { 
     
    10321032                $res = $this->close(); 
    10331033            else 
    1034                 $res = $this->expunge($mailbox); 
    1035         } 
    1036  
    1037             return $res; 
     1034                $res = $this->expunge($mailbox); 
     1035        } 
     1036 
     1037        return $res; 
    10381038    } 
    10391039 
     
    10481048    function countMessages($mailbox, $refresh = false) 
    10491049    { 
    1050             if ($refresh) { 
    1051                     $this->selected = ''; 
    1052             } 
    1053  
    1054             if ($this->selected == $mailbox) { 
    1055                     return $this->data['EXISTS']; 
    1056             } 
     1050        if ($refresh) { 
     1051            $this->selected = ''; 
     1052        } 
     1053 
     1054        if ($this->selected == $mailbox) { 
     1055            return $this->data['EXISTS']; 
     1056        } 
    10571057 
    10581058        // Check internal cache 
     
    10811081    function countRecent($mailbox) 
    10821082    { 
    1083             if (!strlen($mailbox)) { 
    1084                     $mailbox = 'INBOX'; 
    1085             } 
    1086  
    1087             $this->select($mailbox); 
    1088  
    1089             if ($this->selected == $mailbox) { 
    1090                     return $this->data['RECENT']; 
    1091             } 
    1092  
    1093             return false; 
     1083        if (!strlen($mailbox)) { 
     1084            $mailbox = 'INBOX'; 
     1085        } 
     1086 
     1087        $this->select($mailbox); 
     1088 
     1089        if ($this->selected == $mailbox) { 
     1090            return $this->data['RECENT']; 
     1091        } 
     1092 
     1093        return false; 
    10941094    } 
    10951095 
     
    11271127    function sort($mailbox, $field, $add='', $is_uid=FALSE, $encoding = 'US-ASCII') 
    11281128    { 
    1129             $field = strtoupper($field); 
    1130             if ($field == 'INTERNALDATE') { 
    1131                 $field = 'ARRIVAL'; 
    1132             } 
    1133  
    1134             $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1, 
     1129        $field = strtoupper($field); 
     1130        if ($field == 'INTERNALDATE') { 
     1131            $field = 'ARRIVAL'; 
     1132        } 
     1133 
     1134        $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1, 
    11351135            'FROM' => 1, 'SIZE' => 1, 'SUBJECT' => 1, 'TO' => 1); 
    11361136 
    1137             if (!$fields[$field]) { 
    1138                 return false; 
    1139             } 
    1140  
    1141             if (!$this->select($mailbox)) { 
    1142                 return false; 
    1143             } 
    1144  
    1145             // message IDs 
    1146             if (!empty($add)) 
    1147                     $add = $this->compressMessageSet($add); 
    1148  
    1149             list($code, $response) = $this->execute($is_uid ? 'UID SORT' : 'SORT', 
    1150                 array("($field)", $encoding, 'ALL' . (!empty($add) ? ' '.$add : ''))); 
    1151  
    1152             if ($code == self::ERROR_OK) { 
    1153                 // remove prefix and \r\n from raw response 
     1137        if (!$fields[$field]) { 
     1138            return false; 
     1139        } 
     1140 
     1141        if (!$this->select($mailbox)) { 
     1142            return false; 
     1143        } 
     1144 
     1145        // message IDs 
     1146        if (!empty($add)) 
     1147            $add = $this->compressMessageSet($add); 
     1148 
     1149        list($code, $response) = $this->execute($is_uid ? 'UID SORT' : 'SORT', 
     1150            array("($field)", $encoding, 'ALL' . (!empty($add) ? ' '.$add : ''))); 
     1151 
     1152        if ($code == self::ERROR_OK) { 
     1153            // remove prefix and \r\n from raw response 
    11541154            $response = str_replace("\r\n", '', substr($response, 7)); 
    1155                 return preg_split('/\s+/', $response, -1, PREG_SPLIT_NO_EMPTY); 
    1156             } 
     1155            return preg_split('/\s+/', $response, -1, PREG_SPLIT_NO_EMPTY); 
     1156        } 
    11571157 
    11581158        return false; 
     
    11611161    function fetchHeaderIndex($mailbox, $message_set, $index_field='', $skip_deleted=true, $uidfetch=false) 
    11621162    { 
    1163             if (is_array($message_set)) { 
    1164                     if (!($message_set = $this->compressMessageSet($message_set))) 
    1165                             return false; 
    1166             } else { 
    1167                     list($from_idx, $to_idx) = explode(':', $message_set); 
    1168                     if (empty($message_set) || 
    1169                             (isset($to_idx) && $to_idx != '*' && (int)$from_idx > (int)$to_idx)) { 
    1170                             return false; 
    1171                     } 
    1172             } 
    1173  
    1174             $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field); 
    1175  
    1176         $fields_a['DATE']         = 1; 
    1177             $fields_a['INTERNALDATE'] = 4; 
    1178         $fields_a['ARRIVAL']      = 4; 
    1179             $fields_a['FROM']         = 1; 
    1180         $fields_a['REPLY-TO']     = 1; 
    1181             $fields_a['SENDER']       = 1; 
    1182         $fields_a['TO']           = 1; 
    1183             $fields_a['CC']           = 1; 
    1184         $fields_a['SUBJECT']      = 1; 
    1185             $fields_a['UID']          = 2; 
    1186         $fields_a['SIZE']         = 2; 
    1187             $fields_a['SEEN']         = 3; 
    1188         $fields_a['RECENT']       = 3; 
    1189             $fields_a['DELETED']      = 3; 
    1190  
    1191         if (!($mode = $fields_a[$index_field])) { 
    1192                 return false; 
    1193             } 
    1194  
    1195         /*  Do "SELECT" command */ 
    1196             if (!$this->select($mailbox)) { 
    1197                     return false; 
    1198             } 
    1199  
    1200         // build FETCH command string 
    1201             $key     = $this->nextTag(); 
    1202             $cmd     = $uidfetch ? 'UID FETCH' : 'FETCH'; 
    1203             $deleted = $skip_deleted ? ' FLAGS' : ''; 
    1204  
    1205             if ($mode == 1 && $index_field == 'DATE') 
    1206                     $request = " $cmd $message_set (INTERNALDATE BODY.PEEK[HEADER.FIELDS (DATE)]$deleted)"; 
    1207             else if ($mode == 1) 
    1208                     $request = " $cmd $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)]$deleted)"; 
    1209             else if ($mode == 2) { 
    1210                     if ($index_field == 'SIZE') 
    1211                             $request = " $cmd $message_set (RFC822.SIZE$deleted)"; 
    1212                     else 
    1213                             $request = " $cmd $message_set ($index_field$deleted)"; 
    1214             } else if ($mode == 3) 
    1215                     $request = " $cmd $message_set (FLAGS)"; 
    1216             else // 4 
    1217                     $request = " $cmd $message_set (INTERNALDATE$deleted)"; 
    1218  
    1219             $request = $key . $request; 
    1220  
    1221             if (!$this->putLine($request)) { 
     1163        if (is_array($message_set)) { 
     1164            if (!($message_set = $this->compressMessageSet($message_set))) 
     1165                return false; 
     1166        } else { 
     1167            list($from_idx, $to_idx) = explode(':', $message_set); 
     1168            if (empty($message_set) || 
     1169                (isset($to_idx) && $to_idx != '*' && (int)$from_idx > (int)$to_idx)) { 
     1170                return false; 
     1171            } 
     1172        } 
     1173 
     1174        $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field); 
     1175 
     1176        $fields_a['DATE']         = 1; 
     1177        $fields_a['INTERNALDATE'] = 4; 
     1178        $fields_a['ARRIVAL']      = 4; 
     1179        $fields_a['FROM']         = 1; 
     1180        $fields_a['REPLY-TO']     = 1; 
     1181        $fields_a['SENDER']       = 1; 
     1182        $fields_a['TO']           = 1; 
     1183        $fields_a['CC']           = 1; 
     1184        $fields_a['SUBJECT']      = 1; 
     1185        $fields_a['UID']          = 2; 
     1186        $fields_a['SIZE']         = 2; 
     1187        $fields_a['SEEN']         = 3; 
     1188        $fields_a['RECENT']       = 3; 
     1189        $fields_a['DELETED']      = 3; 
     1190 
     1191        if (!($mode = $fields_a[$index_field])) { 
     1192            return false; 
     1193        } 
     1194 
     1195        /*  Do "SELECT" command */ 
     1196        if (!$this->select($mailbox)) { 
     1197            return false; 
     1198        } 
     1199 
     1200        // build FETCH command string 
     1201        $key     = $this->nextTag(); 
     1202        $cmd     = $uidfetch ? 'UID FETCH' : 'FETCH'; 
     1203        $deleted = $skip_deleted ? ' FLAGS' : ''; 
     1204 
     1205        if ($mode == 1 && $index_field == 'DATE') 
     1206            $request = " $cmd $message_set (INTERNALDATE BODY.PEEK[HEADER.FIELDS (DATE)]$deleted)"; 
     1207        else if ($mode == 1) 
     1208            $request = " $cmd $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)]$deleted)"; 
     1209        else if ($mode == 2) { 
     1210            if ($index_field == 'SIZE') 
     1211                $request = " $cmd $message_set (RFC822.SIZE$deleted)"; 
     1212            else 
     1213                $request = " $cmd $message_set ($index_field$deleted)"; 
     1214        } else if ($mode == 3) 
     1215            $request = " $cmd $message_set (FLAGS)"; 
     1216        else // 4 
     1217            $request = " $cmd $message_set (INTERNALDATE$deleted)"; 
     1218 
     1219        $request = $key . $request; 
     1220 
     1221        if (!$this->putLine($request)) { 
    12221222            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); 
    1223                     return false; 
    1224         } 
    1225  
    1226             $result = array(); 
    1227  
    1228             do { 
    1229                     $line = rtrim($this->readLine(200)); 
    1230                     $line = $this->multLine($line); 
    1231  
    1232                     if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { 
    1233                 $id     = $m[1]; 
    1234                             $flags  = NULL; 
    1235  
    1236                             if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { 
    1237                                     $flags = explode(' ', strtoupper($matches[1])); 
    1238                                     if (in_array('\\DELETED', $flags)) { 
    1239                                             $deleted[$id] = $id; 
    1240                                             continue; 
    1241                                     } 
    1242                             } 
    1243  
    1244                             if ($mode == 1 && $index_field == 'DATE') { 
    1245                                     if (preg_match('/BODY\[HEADER\.FIELDS \("*DATE"*\)\] (.*)/', $line, $matches)) { 
    1246                                             $value = preg_replace(array('/^"*[a-z]+:/i'), '', $matches[1]); 
    1247                                             $value = trim($value); 
    1248                                             $result[$id] = $this->strToTime($value); 
    1249                                     } 
    1250                                     // non-existent/empty Date: header, use INTERNALDATE 
    1251                                     if (empty($result[$id])) { 
    1252                                             if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) 
    1253                                                     $result[$id] = $this->strToTime($matches[1]); 
    1254                                             else 
    1255                                                     $result[$id] = 0; 
    1256                                     } 
    1257                             } else if ($mode == 1) { 
    1258                                     if (preg_match('/BODY\[HEADER\.FIELDS \("?(FROM|REPLY-TO|SENDER|TO|SUBJECT)"?\)\] (.*)/', $line, $matches)) { 
    1259                                             $value = preg_replace(array('/^"*[a-z]+:/i', '/\s+$/sm'), array('', ''), $matches[2]); 
    1260                                             $result[$id] = trim($value); 
    1261                                     } else { 
    1262                                             $result[$id] = ''; 
    1263                                     } 
    1264                             } else if ($mode == 2) { 
    1265                                     if (preg_match('/\((UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) { 
    1266                                             $result[$id] = trim($matches[2]); 
    1267                                     } else { 
    1268                                             $result[$id] = 0; 
    1269                                     } 
    1270                             } else if ($mode == 3) { 
    1271                                     if (!$flags && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { 
    1272                                             $flags = explode(' ', $matches[1]); 
    1273                                     } 
    1274                                     $result[$id] = in_array('\\'.$index_field, $flags) ? 1 : 0; 
    1275                             } else if ($mode == 4) { 
    1276                                     if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) { 
    1277                                             $result[$id] = $this->strToTime($matches[1]); 
    1278                                     } else { 
    1279                                             $result[$id] = 0; 
    1280                                     } 
    1281                             } 
    1282                     } 
    1283             } while (!$this->startsWith($line, $key, true, true)); 
    1284  
    1285             return $result; 
     1223            return false; 
     1224        } 
     1225 
     1226        $result = array(); 
     1227 
     1228        do { 
     1229            $line = rtrim($this->readLine(200)); 
     1230            $line = $this->multLine($line); 
     1231 
     1232            if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { 
     1233                $id     = $m[1]; 
     1234                $flags  = NULL; 
     1235 
     1236                if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { 
     1237                    $flags = explode(' ', strtoupper($matches[1])); 
     1238                    if (in_array('\\DELETED', $flags)) { 
     1239                        $deleted[$id] = $id; 
     1240                        continue; 
     1241                    } 
     1242                } 
     1243 
     1244                if ($mode == 1 && $index_field == 'DATE') { 
     1245                    if (preg_match('/BODY\[HEADER\.FIELDS \("*DATE"*\)\] (.*)/', $line, $matches)) { 
     1246                        $value = preg_replace(array('/^"*[a-z]+:/i'), '', $matches[1]); 
     1247                        $value = trim($value); 
     1248                        $result[$id] = $this->strToTime($value); 
     1249                    } 
     1250                    // non-existent/empty Date: header, use INTERNALDATE 
     1251                    if (empty($result[$id])) { 
     1252                        if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) 
     1253                            $result[$id] = $this->strToTime($matches[1]); 
     1254                        else 
     1255                            $result[$id] = 0; 
     1256                    } 
     1257                } else if ($mode == 1) { 
     1258                    if (preg_match('/BODY\[HEADER\.FIELDS \("?(FROM|REPLY-TO|SENDER|TO|SUBJECT)"?\)\] (.*)/', $line, $matches)) { 
     1259                        $value = preg_replace(array('/^"*[a-z]+:/i', '/\s+$/sm'), array('', ''), $matches[2]); 
     1260                        $result[$id] = trim($value); 
     1261                    } else { 
     1262                        $result[$id] = ''; 
     1263                    } 
     1264                } else if ($mode == 2) { 
     1265                    if (preg_match('/\((UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) { 
     1266                        $result[$id] = trim($matches[2]); 
     1267                    } else { 
     1268                        $result[$id] = 0; 
     1269                    } 
     1270                } else if ($mode == 3) { 
     1271                    if (!$flags && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { 
     1272                        $flags = explode(' ', $matches[1]); 
     1273                    } 
     1274                    $result[$id] = in_array('\\'.$index_field, $flags) ? 1 : 0; 
     1275                } else if ($mode == 4) { 
     1276                    if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) { 
     1277                        $result[$id] = $this->strToTime($matches[1]); 
     1278                    } else { 
     1279                        $result[$id] = 0; 
     1280                    } 
     1281                } 
     1282            } 
     1283        } while (!$this->startsWith($line, $key, true, true)); 
     1284 
     1285        return $result; 
    12861286    } 
    12871287 
    12881288    static function compressMessageSet($messages, $force=false) 
    12891289    { 
    1290             // given a comma delimited list of independent mid's, 
    1291             // compresses by grouping sequences together 
     1290        // given a comma delimited list of independent mid's, 
     1291        // compresses by grouping sequences together 
    12921292 
    12931293        if (!is_array($messages)) { 
    1294                 // if less than 255 bytes long, let's not bother 
    1295                 if (!$force && strlen($messages)<255) { 
    1296                     return $messages; 
    1297                 } 
    1298  
    1299             // see if it's already been compressed 
    1300                 if (strpos($messages, ':') !== false) { 
    1301                     return $messages; 
    1302                 } 
    1303  
    1304                 // separate, then sort 
    1305                 $messages = explode(',', $messages); 
    1306         } 
    1307  
    1308             sort($messages); 
    1309  
    1310             $result = array(); 
    1311             $start  = $prev = $messages[0]; 
    1312  
    1313             foreach ($messages as $id) { 
    1314                     $incr = $id - $prev; 
    1315                     if ($incr > 1) {                    //found a gap 
    1316                             if ($start == $prev) { 
    1317                                 $result[] = $prev;      //push single id 
    1318                             } else { 
    1319                                 $result[] = $start . ':' . $prev;   //push sequence as start_id:end_id 
    1320                             } 
    1321                         $start = $id;                   //start of new sequence 
    1322                     } 
    1323                     $prev = $id; 
    1324             } 
    1325  
    1326             // handle the last sequence/id 
    1327             if ($start == $prev) { 
    1328                 $result[] = $prev; 
    1329             } else { 
    1330             $result[] = $start.':'.$prev; 
    1331             } 
    1332  
    1333             // return as comma separated string 
    1334             return implode(',', $result); 
     1294            // if less than 255 bytes long, let's not bother 
     1295            if (!$force && strlen($messages)<255) { 
     1296                return $messages; 
     1297           } 
     1298 
     1299            // see if it's already been compressed 
     1300            if (strpos($messages, ':') !== false) { 
     1301                return $messages; 
     1302            } 
     1303 
     1304            // separate, then sort 
     1305            $messages = explode(',', $messages); 
     1306        } 
     1307 
     1308        sort($messages); 
     1309 
     1310        $result = array(); 
     1311        $start  = $prev = $messages[0]; 
     1312 
     1313        foreach ($messages as $id) { 
     1314            $incr = $id - $prev; 
     1315            if ($incr > 1) { // found a gap 
     1316                if ($start == $prev) { 
     1317                    $result[] = $prev; // push single id 
     1318                } else { 
     1319                    $result[] = $start . ':' . $prev; // push sequence as start_id:end_id 
     1320                } 
     1321                $start = $id; // start of new sequence 
     1322            } 
     1323            $prev = $id; 
     1324        } 
     1325 
     1326        // handle the last sequence/id 
     1327        if ($start == $prev) { 
     1328            $result[] = $prev; 
     1329        } else { 
     1330            $result[] = $start.':'.$prev; 
     1331        } 
     1332 
     1333        // return as comma separated string 
     1334        return implode(',', $result); 
    13351335    } 
    13361336 
    13371337    static function uncompressMessageSet($messages) 
    13381338    { 
    1339             $result   = array(); 
    1340             $messages = explode(',', $messages); 
     1339        $result   = array(); 
     1340        $messages = explode(',', $messages); 
    13411341 
    13421342        foreach ($messages as $part) { 
     
    13631363    function UID2ID($mailbox, $uid) 
    13641364    { 
    1365             if ($uid > 0) { 
    1366                 $id_a = $this->search($mailbox, "UID $uid"); 
    1367                 if (is_array($id_a) && count($id_a) == 1) { 
    1368                         return (int) $id_a[0]; 
    1369                     } 
    1370             } 
    1371             return null; 
     1365        if ($uid > 0) { 
     1366            $id_a = $this->search($mailbox, "UID $uid"); 
     1367            if (is_array($id_a) && count($id_a) == 1) { 
     1368                return (int) $id_a[0]; 
     1369            } 
     1370        } 
     1371        return null; 
    13721372    } 
    13731373 
     
    13831383    function ID2UID($mailbox, $id) 
    13841384    { 
    1385             if (empty($id) || $id < 0) { 
    1386                 return  null; 
    1387             } 
    1388  
    1389         if (!$this->select($mailbox)) { 
     1385        if (empty($id) || $id < 0) { 
     1386            return      null; 
     1387        } 
     1388 
     1389        if (!$this->select($mailbox)) { 
    13901390            return null; 
    13911391        } 
     
    13941394 
    13951395        if ($code == self::ERROR_OK && preg_match("/^\* $id FETCH \(UID (.*)\)/i", $response, $m)) { 
    1396                         return (int) $m[1]; 
    1397         } 
    1398  
    1399         return null; 
     1396            return (int) $m[1]; 
     1397        } 
     1398 
     1399        return null; 
    14001400    } 
    14011401 
    14021402    function fetchUIDs($mailbox, $message_set=null) 
    14031403    { 
    1404             if (is_array($message_set)) 
    1405                     $message_set = join(',', $message_set); 
     1404        if (is_array($message_set)) 
     1405            $message_set = join(',', $message_set); 
    14061406        else if (empty($message_set)) 
    1407                     $message_set = '1:*'; 
    1408  
    1409             return $this->fetchHeaderIndex($mailbox, $message_set, 'UID', false); 
     1407            $message_set = '1:*'; 
     1408 
     1409        return $this->fetchHeaderIndex($mailbox, $message_set, 'UID', false); 
    14101410    } 
    14111411 
    14121412    function fetchHeaders($mailbox, $message_set, $uidfetch=false, $bodystr=false, $add='') 
    14131413    { 
    1414             $result = array(); 
    1415  
    1416             if (!$this->select($mailbox)) { 
    1417                     return false; 
    1418             } 
    1419  
    1420             $message_set = $this->compressMessageSet($message_set); 
    1421  
    1422             if ($add) 
    1423                     $add = ' '.trim($add); 
    1424  
    1425             /* FETCH uid, size, flags and headers */ 
    1426             $key          = $this->nextTag(); 
    1427             $request  = $key . ($uidfetch ? ' UID' : '') . " FETCH $message_set "; 
    1428             $request .= "(UID RFC822.SIZE FLAGS INTERNALDATE "; 
    1429             if ($bodystr) 
    1430                     $request .= "BODYSTRUCTURE "; 
    1431             $request .= "BODY.PEEK[HEADER.FIELDS (DATE FROM TO SUBJECT CONTENT-TYPE "; 
    1432             $request .= "LIST-POST DISPOSITION-NOTIFICATION-TO".$add.")])"; 
    1433  
    1434             if (!$this->putLine($request)) { 
     1414        $result = array(); 
     1415 
     1416        if (!$this->select($mailbox)) { 
     1417            return false; 
     1418        } 
     1419 
     1420        $message_set = $this->compressMessageSet($message_set); 
     1421 
     1422        if ($add) 
     1423            $add = ' '.trim($add); 
     1424 
     1425        /* FETCH uid, size, flags and headers */ 
     1426        $key      = $this->nextTag(); 
     1427        $request  = $key . ($uidfetch ? ' UID' : '') . " FETCH $message_set "; 
     1428        $request .= "(UID RFC822.SIZE FLAGS INTERNALDATE "; 
     1429        if ($bodystr) 
     1430            $request .= "BODYSTRUCTURE "; 
     1431        $request .= "BODY.PEEK[HEADER.FIELDS (DATE FROM TO SUBJECT CONTENT-TYPE "; 
     1432        $request .= "LIST-POST DISPOSITION-NOTIFICATION-TO".$add.")])"; 
     1433 
     1434        if (!$this->putLine($request)) { 
    14351435            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); 
    1436                     return false; 
    1437             } 
    1438             do { 
    1439                     $line = $this->readLine(4096); 
    1440                     $line = $this->multLine($line); 
     1436            return false; 
     1437        } 
     1438        do { 
     1439            $line = $this->readLine(4096); 
     1440            $line = $this->multLine($line); 
    14411441 
    14421442            if (!$line) 
    14431443                break; 
    14441444 
    1445                     if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { 
    1446                             $id = intval($m[1]); 
    1447  
    1448                             $result[$id]            = new rcube_mail_header; 
    1449                             $result[$id]->id        = $id; 
    1450                             $result[$id]->subject   = ''; 
    1451                             $result[$id]->messageID = 'mid:' . $id; 
    1452  
    1453                             $lines = array(); 
    1454                             $ln = 0; 
    1455  
    1456                             // Sample reply line: 
    1457                             // * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen) 
    1458                             // INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...) 
    1459                             // BODY[HEADER.FIELDS ... 
    1460  
    1461                             if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/s', $line, $matches)) { 
    1462                                     $str = $matches[1]; 
    1463  
    1464                                     // swap parents with quotes, then explode 
    1465                                     $str = preg_replace('/[()]/', '"', $str); 
    1466                                     $a = rcube_explode_quoted_string(' ', $str); 
    1467  
    1468                                     // did we get the right number of replies? 
    1469                                     $parts_count = count($a); 
    1470                                     if ($parts_count>=6) { 
    1471                                             for ($i=0; $i<$parts_count; $i=$i+2) { 
    1472                                                     if ($a[$i] == 'UID') 
    1473                                                             $result[$id]->uid = intval($a[$i+1]); 
    1474                                                     else if ($a[$i] == 'RFC822.SIZE') 
    1475                                                             $result[$id]->size = intval($a[$i+1]); 
    1476                                                 else if ($a[$i] == 'INTERNALDATE') 
    1477                                                         $time_str = $a[$i+1]; 
    1478                                                 else if ($a[$i] == 'FLAGS') 
    1479                                                         $flags_str = $a[$i+1]; 
    1480                                         } 
    1481  
    1482                                             $time_str = str_replace('"', '', $time_str); 
    1483  
    1484                                             // if time is gmt... 
    1485                                 $time_str = str_replace('GMT','+0000',$time_str); 
    1486  
    1487                                             $result[$id]->internaldate = $time_str; 
    1488                                         $result[$id]->timestamp = $this->StrToTime($time_str); 
    1489                                         $result[$id]->date = $time_str; 
    1490                                 } 
    1491  
    1492                                 // BODYSTRUCTURE 
    1493                                     if($bodystr) { 
    1494                                             while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) { 
    1495                                                     $line2 = $this->readLine(1024); 
    1496                                                 $line .= $this->multLine($line2, true); 
    1497                                         } 
    1498                                         $result[$id]->body_structure = $m[1]; 
    1499                                 } 
    1500  
    1501                                 // the rest of the result 
    1502                                 preg_match('/ BODY\[HEADER.FIELDS \(.*?\)\]\s*(.*)$/s', $line, $m); 
    1503                                 $reslines = explode("\n", trim($m[1], '"')); 
    1504                                 // re-parse (see below) 
    1505                                     foreach ($reslines as $resln) { 
    1506                                         if (ord($resln[0])<=32) { 
    1507                                                 $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($resln); 
    1508                                         } else { 
    1509                                                 $lines[++$ln] = trim($resln); 
    1510                                             } 
    1511                                 } 
    1512                         } 
    1513  
    1514                                 // Start parsing headers.  The problem is, some header "lines" take up multiple lines. 
    1515                                 // So, we'll read ahead, and if the one we're reading now is a valid header, we'll 
    1516                                 // process the previous line.  Otherwise, we'll keep adding the strings until we come 
    1517                                 // to the next valid header line. 
    1518  
    1519                             do { 
    1520                                     $line = rtrim($this->readLine(300), "\r\n"); 
    1521  
    1522                                 // The preg_match below works around communigate imap, which outputs " UID <number>)". 
    1523                                 // Without this, the while statement continues on and gets the "FH0 OK completed" message. 
    1524                                 // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. 
    1525                                 // This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing 
    1526                                     // If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin 
    1527                                 // An alternative might be: 
    1528                                 // if (!preg_match("/:/",$line) && preg_match("/\)$/",$line)) break; 
    1529                                 // however, unsure how well this would work with all imap clients. 
    1530                                 if (preg_match("/^\s*UID [0-9]+\)$/", $line)) { 
    1531                                         break; 
    1532                                     } 
    1533  
    1534                                 // handle FLAGS reply after headers (AOL, Zimbra?) 
    1535                                 if (preg_match('/\s+FLAGS \((.*)\)\)$/', $line, $matches)) { 
    1536                                         $flags_str = $matches[1]; 
    1537                                         break; 
    1538                                     } 
    1539  
    1540                                 if (ord($line[0])<=32) { 
    1541                                         $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line); 
    1542                                 } else { 
    1543                                         $lines[++$ln] = trim($line); 
    1544                                     } 
    1545                         // patch from "Maksim Rubis" <siburny@hotmail.com> 
    1546                         } while ($line[0] != ')' && !$this->startsWith($line, $key, true)); 
    1547  
    1548                         if (strncmp($line, $key, strlen($key))) { 
    1549                                 // process header, fill rcube_mail_header obj. 
    1550                                 // initialize 
    1551                                 if (is_array($headers)) { 
    1552                                         reset($headers); 
    1553                                             while (list($k, $bar) = each($headers)) { 
    1554                                                 $headers[$k] = ''; 
    1555                                         } 
    1556                                 } 
    1557  
    1558                                 // create array with header field:data 
    1559                                 while ( list($lines_key, $str) = each($lines) ) { 
    1560                                         list($field, $string) = $this->splitHeaderLine($str); 
    1561  
    1562                                         $field  = strtolower($field); 
    1563                                         $string = preg_replace('/\n\s*/', ' ', $string); 
    1564  
    1565                                         switch ($field) { 
    1566                                         case 'date'; 
    1567                                                 $result[$id]->date = $string; 
    1568                                                 $result[$id]->timestamp = $this->strToTime($string); 
    1569                                         break; 
    1570                                         case 'from': 
    1571                                                 $result[$id]->from = $string; 
    1572                                                 break; 
    1573                                         case 'to': 
    1574                                                 $result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string); 
    1575                                                 break; 
    1576                                         case 'subject': 
    1577                                                 $result[$id]->subject = $string; 
    1578                                                 break; 
    1579                                         case 'reply-to': 
    1580                                                 $result[$id]->replyto = $string; 
    1581                                                 break; 
    1582                                         case 'cc': 
    1583                                                 $result[$id]->cc = $string; 
    1584                                                 break; 
    1585                                         case 'bcc': 
    1586                                                 $result[$id]->bcc = $string; 
    1587                                                 break; 
    1588                                         case 'content-transfer-encoding': 
    1589                                                 $result[$id]->encoding = $string; 
    1590                                                 break; 
    1591                                         case 'content-type': 
    1592                                                 $ctype_parts = preg_split('/[; ]/', $string); 
    1593                                                 $result[$id]->ctype = array_shift($ctype_parts); 
    1594                                                 if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) { 
    1595                                                         $result[$id]->charset = $regs[1]; 
    1596                                                 } 
    1597                                                 break; 
    1598                                             case 'in-reply-to': 
    1599                                                 $result[$id]->in_reply_to = str_replace(array("\n", '<', '>'), '', $string); 
    1600                                                 break; 
    1601                                         case 'references': 
    1602                                                 $result[$id]->references = $string; 
    1603                                                 break; 
    1604                                         case 'return-receipt-to': 
    1605                                         case 'disposition-notification-to': 
    1606                                             case 'x-confirm-reading-to': 
    1607                                                 $result[$id]->mdn_to = $string; 
    1608                                                 break; 
    1609                                         case 'message-id': 
    1610                                                 $result[$id]->messageID = $string; 
    1611                                                 break; 
    1612                                             case 'x-priority': 
    1613                                                 if (preg_match('/^(\d+)/', $string, $matches)) 
    1614                                                         $result[$id]->priority = intval($matches[1]); 
    1615                                                 break; 
    1616                                         default: 
    1617                                                 if (strlen($field) > 2) 
    1618                                                         $result[$id]->others[$field] = $string; 
    1619                                                     break; 
    1620                                         } // end switch () 
    1621                                 } // end while () 
    1622                             } 
    1623  
    1624                         // process flags 
    1625                         if (!empty($flags_str)) { 
    1626                                 $flags_str = preg_replace('/[\\\"]/', '', $flags_str); 
    1627                                 $flags_a   = explode(' ', $flags_str); 
    1628  
    1629                                     if (is_array($flags_a)) { 
    1630                                         foreach($flags_a as $flag) { 
    1631                                                 $flag = strtoupper($flag); 
    1632                                                 if ($flag == 'SEEN') { 
    1633                                                     $result[$id]->seen = true; 
    1634                                                 } else if ($flag == 'DELETED') { 
    1635                                                     $result[$id]->deleted = true; 
    1636                                                 } else if ($flag == 'RECENT') { 
    1637                                                     $result[$id]->recent = true; 
    1638                                                 } else if ($flag == 'ANSWERED') { 
    1639                                                         $result[$id]->answered = true; 
    1640                                                 } else if ($flag == '$FORWARDED') { 
    1641                                                         $result[$id]->forwarded = true; 
    1642                                                 } else if ($flag == 'DRAFT') { 
    1643                                                         $result[$id]->is_draft = true; 
    1644                                                 } else if ($flag == '$MDNSENT') { 
    1645                                                         $result[$id]->mdn_sent = true; 
    1646                                                 } else if ($flag == 'FLAGGED') { 
    1647                                                          $result[$id]->flagged = true; 
    1648                                                     } 
    1649                                         } 
    1650                                         $result[$id]->flags = $flags_a; 
    1651                                 } 
    1652                             } 
    1653                 } 
    1654             } while (!$this->startsWith($line, $key, true)); 
    1655  
    1656         return $result; 
     1445            if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { 
     1446                $id = intval($m[1]); 
     1447 
     1448                $result[$id]            = new rcube_mail_header; 
     1449                $result[$id]->id        = $id; 
     1450                $result[$id]->subject   = ''; 
     1451                $result[$id]->messageID = 'mid:' . $id; 
     1452 
     1453                $lines = array(); 
     1454                $ln = 0; 
     1455 
     1456                // Sample reply line: 
     1457                // * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen) 
     1458                // INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...) 
     1459                // BODY[HEADER.FIELDS ... 
     1460 
     1461                if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/s', $line, $matches)) { 
     1462                    $str = $matches[1]; 
     1463 
     1464                    // swap parents with quotes, then explode 
     1465                    $str = preg_replace('/[()]/', '"', $str); 
     1466                    $a = rcube_explode_quoted_string(' ', $str); 
     1467 
     1468                    // did we get the right number of replies? 
     1469                    $parts_count = count($a); 
     1470                    if ($parts_count>=6) { 
     1471                        for ($i=0; $i<$parts_count; $i=$i+2) { 
     1472                            if ($a[$i] == 'UID') { 
     1473                                $result[$id]->uid = intval($a[$i+1]); 
     1474                            } 
     1475                            else if ($a[$i] == 'RFC822.SIZE') { 
     1476                                $result[$id]->size = intval($a[$i+1]); 
     1477                            } 
     1478                            else if ($a[$i] == 'INTERNALDATE') { 
     1479                                $time_str = $a[$i+1]; 
     1480                            } 
     1481                            else if ($a[$i] == 'FLAGS') { 
     1482                                $flags_str = $a[$i+1]; 
     1483                            } 
     1484                        } 
     1485 
     1486                        $time_str = str_replace('"', '', $time_str); 
     1487 
     1488                        // if time is gmt... 
     1489                        $time_str = str_replace('GMT','+0000',$time_str); 
     1490 
     1491                        $result[$id]->internaldate = $time_str; 
     1492                        $result[$id]->timestamp    = $this->StrToTime($time_str); 
     1493                        $result[$id]->date         = $time_str; 
     1494                    } 
     1495 
     1496                    // BODYSTRUCTURE 
     1497                    if ($bodystr) { 
     1498                        while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) { 
     1499                            $line2 = $this->readLine(1024); 
     1500                            $line .= $this->multLine($line2, true); 
     1501                        } 
     1502                        $result[$id]->body_structure = $m[1]; 
     1503                    } 
     1504 
     1505                    // the rest of the result 
     1506                    if (preg_match('/ BODY\[HEADER.FIELDS \(.*?\)\]\s*(.*)$/s', $line, $m)) { 
     1507                        $reslines = explode("\n", trim($m[1], '"')); 
     1508                        // re-parse (see below) 
     1509                        foreach ($reslines as $resln) { 
     1510                            if (ord($resln[0])<=32) { 
     1511                                $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($resln); 
     1512                            } else { 
     1513                                $lines[++$ln] = trim($resln); 
     1514                            } 
     1515                        } 
     1516                    } 
     1517                } 
     1518 
     1519                // Start parsing headers.  The problem is, some header "lines" take up multiple lines. 
     1520                // So, we'll read ahead, and if the one we're reading now is a valid header, we'll 
     1521                // process the previous line.  Otherwise, we'll keep adding the strings until we come 
     1522                // to the next valid header line. 
     1523 
     1524                do { 
     1525                    $line = rtrim($this->readLine(300), "\r\n"); 
     1526 
     1527                    // The preg_match below works around communigate imap, which outputs " UID <number>)". 
     1528                    // Without this, the while statement continues on and gets the "FH0 OK completed" message. 
     1529                    // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. 
     1530                    // This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing 
     1531                    // If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin 
     1532                    // An alternative might be: 
     1533                    // if (!preg_match("/:/",$line) && preg_match("/\)$/",$line)) break; 
     1534                    // however, unsure how well this would work with all imap clients. 
     1535                    if (preg_match("/^\s*UID [0-9]+\)$/", $line)) { 
     1536                        break; 
     1537                    } 
     1538 
     1539                    // handle FLAGS reply after headers (AOL, Zimbra?) 
     1540                    if (preg_match('/\s+FLAGS \((.*)\)\)$/', $line, $matches)) { 
     1541                        $flags_str = $matches[1]; 
     1542                        break; 
     1543                    } 
     1544 
     1545                    if (ord($line[0])<=32) { 
     1546                        $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line); 
     1547                    } else { 
     1548                        $lines[++$ln] = trim($line); 
     1549                    } 
     1550                // patch from "Maksim Rubis" <siburny@hotmail.com> 
     1551                } while ($line[0] != ')' && !$this->startsWith($line, $key, true)); 
     1552 
     1553                if (strncmp($line, $key, strlen($key))) { 
     1554                    // process header, fill rcube_mail_header obj. 
     1555                    // initialize 
     1556                    if (is_array($headers)) { 
     1557                        reset($headers); 
     1558                        while (list($k, $bar) = each($headers)) { 
     1559                            $headers[$k] = ''; 
     1560                        } 
     1561                    } 
     1562 
     1563                    // create array with header field:data 
     1564                    while (list($lines_key, $str) = each($lines)) { 
     1565                        list($field, $string) = $this->splitHeaderLine($str); 
     1566 
     1567                        $field  = strtolower($field); 
     1568                        $string = preg_replace('/\n\s*/', ' ', $string); 
     1569 
     1570                        switch ($field) { 
     1571                        case 'date'; 
     1572                            $result[$id]->date = $string; 
     1573                            $result[$id]->timestamp = $this->strToTime($string); 
     1574                            break; 
     1575                        case 'from': 
     1576                            $result[$id]->from = $string; 
     1577                            break; 
     1578                        case 'to': 
     1579                            $result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string); 
     1580                            break; 
     1581                        case 'subject': 
     1582                            $result[$id]->subject = $string; 
     1583                            break; 
     1584                        case 'reply-to': 
     1585                            $result[$id]->replyto = $string; 
     1586                            break; 
     1587                        case 'cc': 
     1588                            $result[$id]->cc = $string; 
     1589                            break; 
     1590                        case 'bcc': 
     1591                            $result[$id]->bcc = $string; 
     1592                            break; 
     1593                        case 'content-transfer-encoding': 
     1594                            $result[$id]->encoding = $string; 
     1595                        break; 
     1596                        case 'content-type': 
     1597                            $ctype_parts = preg_split('/[; ]/', $string); 
     1598                            $result[$id]->ctype = array_shift($ctype_parts); 
     1599                            if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) { 
     1600                                $result[$id]->charset = $regs[1]; 
     1601                            } 
     1602                            break; 
     1603                        case 'in-reply-to': 
     1604                            $result[$id]->in_reply_to = str_replace(array("\n", '<', '>'), '', $string); 
     1605                            break; 
     1606                        case 'references': 
     1607                            $result[$id]->references = $string; 
     1608                            break; 
     1609                        case 'return-receipt-to': 
     1610                        case 'disposition-notification-to': 
     1611                        case 'x-confirm-reading-to': 
     1612                            $result[$id]->mdn_to = $string; 
     1613                            break; 
     1614                        case 'message-id': 
     1615                            $result[$id]->messageID = $string; 
     1616                            break; 
     1617                        case 'x-priority': 
     1618                            if (preg_match('/^(\d+)/', $string, $matches)) { 
     1619                                $result[$id]->priority = intval($matches[1]); 
     1620                            } 
     1621                            break; 
     1622                        default: 
     1623                            if (strlen($field) > 2) { 
     1624                                $result[$id]->others[$field] = $string; 
     1625                            } 
     1626                            break; 
     1627                        } // end switch () 
     1628                    } // end while () 
     1629                } 
     1630 
     1631                // process flags 
     1632                if (!empty($flags_str)) { 
     1633                    $flags_str = preg_replace('/[\\\"]/', '', $flags_str); 
     1634                    $flags_a   = explode(' ', $flags_str); 
     1635 
     1636                    if (is_array($flags_a)) { 
     1637                        foreach($flags_a as $flag) { 
     1638                            $flag = strtoupper($flag); 
     1639                            if ($flag == 'SEEN') { 
     1640                                $result[$id]->seen = true; 
     1641                            } else if ($flag == 'DELETED') { 
     1642                                $result[$id]->deleted = true; 
     1643                            } else if ($flag == 'RECENT') { 
     1644                                $result[$id]->recent = true; 
     1645                            } else if ($flag == 'ANSWERED') { 
     1646                                $result[$id]->answered = true; 
     1647                            } else if ($flag == '$FORWARDED') { 
     1648                                $result[$id]->forwarded = true; 
     1649                            } else if ($flag == 'DRAFT') { 
     1650                                $result[$id]->is_draft = true; 
     1651                            } else if ($flag == '$MDNSENT') { 
     1652                                $result[$id]->mdn_sent = true; 
     1653                            } else if ($flag == 'FLAGGED') { 
     1654                                 $result[$id]->flagged = true; 
     1655                            } 
     1656                        } 
     1657                        $result[$id]->flags = $flags_a; 
     1658                    } 
     1659                } 
     1660            } 
     1661        } while (!$this->startsWith($line, $key, true)); 
     1662 
     1663        return $result; 
    16571664    } 
    16581665 
    16591666    function fetchHeader($mailbox, $id, $uidfetch=false, $bodystr=false, $add='') 
    16601667    { 
    1661             $a  = $this->fetchHeaders($mailbox, $id, $uidfetch, $bodystr, $add); 
    1662             if (is_array($a)) { 
    1663                     return array_shift($a); 
    1664             } 
    1665             return false; 
     1668        $a  = $this->fetchHeaders($mailbox, $id, $uidfetch, $bodystr, $add); 
     1669        if (is_array($a)) { 
     1670            return array_shift($a); 
     1671        } 
     1672        return false; 
    16661673    } 
    16671674 
    16681675    function sortHeaders($a, $field, $flag) 
    16691676    { 
    1670             if (empty($field)) { 
    1671                 $field = 'uid'; 
    1672             } 
     1677        if (empty($field)) { 
     1678            $field = 'uid'; 
     1679        } 
    16731680        else { 
    1674             $field = strtolower($field); 
    1675         } 
    1676  
    1677             if ($field == 'date' || $field == 'internaldate') { 
    1678                 $field = 'timestamp'; 
    1679             } 
    1680  
    1681         if (empty($flag)) { 
    1682                 $flag = 'ASC'; 
    1683             } else { 
    1684                 $flag = strtoupper($flag); 
    1685         } 
    1686  
    1687             $c = count($a); 
    1688             if ($c > 0) { 
    1689                         // Strategy: 
    1690                         // First, we'll create an "index" array. 
    1691                         // Then, we'll use sort() on that array, 
    1692                         // and use that to sort the main array. 
    1693  
    1694                     // create "index" array 
    1695                     $index = array(); 
    1696                     reset($a); 
    1697                     while (list($key, $val) = each($a)) { 
    1698                             if ($field == 'timestamp') { 
    1699                                     $data = $this->strToTime($val->date); 
    1700                                     if (!$data) { 
    1701                                             $data = $val->timestamp; 
    1702                         } 
    1703                             } else { 
    1704                                     $data = $val->$field; 
    1705                                     if (is_string($data)) { 
    1706                                         $data = str_replace('"', '', $data); 
    1707                             if ($field == 'subject') { 
    1708                                             $data = preg_replace('/^(Re: \s*|Fwd:\s*|Fw:\s*)+/i', '', $data); 
     1681            $field = strtolower($field); 
     1682        } 
     1683 
     1684        if ($field == 'date' || $field == 'internaldate') { 
     1685            $field = 'timestamp'; 
     1686        } 
     1687 
     1688        if (empty($flag)) { 
     1689            $flag = 'ASC'; 
     1690        } else { 
     1691            $flag = strtoupper($flag); 
     1692        } 
     1693 
     1694        $c = count($a); 
     1695        if ($c > 0) { 
     1696            // Strategy: 
     1697            // First, we'll create an "index" array. 
     1698            // Then, we'll use sort() on that array, 
     1699            // and use that to sort the main array. 
     1700 
     1701            // create "index" array 
     1702            $index = array(); 
     1703            reset($a); 
     1704            while (list($key, $val) = each($a)) { 
     1705                if ($field == 'timestamp') { 
     1706                    $data = $this->strToTime($val->date); 
     1707                    if (!$data) { 
     1708                        $data = $val->timestamp; 
     1709                    } 
     1710                } else { 
     1711                    $data = $val->$field; 
     1712                    if (is_string($data)) { 
     1713                        $data = str_replace('"', '', $data); 
     1714                        if ($field == 'subject') { 
     1715                            $data = preg_replace('/^(Re: \s*|Fwd:\s*|Fw:\s*)+/i', '', $data); 
    17091716                        } 
    1710                                             $data = strtoupper($data); 
    1711                         } 
    1712                             } 
    1713                         $index[$key] = $data; 
    1714                 } 
    1715  
    1716                     // sort index 
    1717                 if ($flag == 'ASC') { 
    1718                         asort($index); 
    1719                 } else { 
    1720                     arsort($index); 
    1721                     } 
    1722  
    1723                 // form new array based on index 
    1724                 $result = array(); 
    1725                     reset($index); 
    1726                 while (list($key, $val) = each($index)) { 
    1727                         $result[$key] = $a[$key]; 
    1728                     } 
    1729             } 
    1730  
    1731             return $result; 
     1717                        $data = strtoupper($data); 
     1718                    } 
     1719                } 
     1720                $index[$key] = $data; 
     1721            } 
     1722 
     1723            // sort index 
     1724            if ($flag == 'ASC') { 
     1725                asort($index); 
     1726            } else { 
     1727                arsort($index); 
     1728            } 
     1729 
     1730            // form new array based on index 
     1731            $result = array(); 
     1732            reset($index); 
     1733            while (list($key, $val) = each($index)) { 
     1734                $result[$key] = $a[$key]; 
     1735            } 
     1736        } 
     1737 
     1738        return $result; 
    17321739    } 
    17331740 
     
    17351742    function modFlag($mailbox, $messages, $flag, $mod) 
    17361743    { 
    1737             if ($mod != '+' && $mod != '-') { 
     1744        if ($mod != '+' && $mod != '-') { 
    17381745            $mod = '+'; 
    1739             } 
    1740  
    1741             if (!$this->select($mailbox)) { 
    1742                 return false; 
    1743             } 
     1746        } 
     1747 
     1748        if (!$this->select($mailbox)) { 
     1749            return false; 
     1750        } 
    17441751 
    17451752        if (!$this->data['READ-WRITE']) { 
     
    17531760        } 
    17541761 
    1755             $flag   = $this->flags[strtoupper($flag)]; 
     1762        $flag   = $this->flags[strtoupper($flag)]; 
    17561763        $result = $this->execute('UID STORE', array( 
    17571764            $this->compressMessageSet($messages), $mod . 'FLAGS.SILENT', "($flag)"), 
    17581765            self::COMMAND_NORESPONSE); 
    17591766 
    1760             return ($result == self::ERROR_OK); 
     1767        return ($result == self::ERROR_OK); 
    17611768    } 
    17621769 
    17631770    function flag($mailbox, $messages, $flag) { 
    1764             return $this->modFlag($mailbox, $messages, $flag, '+'); 
     1771        return $this->modFlag($mailbox, $messages, $flag, '+'); 
    17651772    } 
    17661773 
    17671774    function unflag($mailbox, $messages, $flag) { 
    1768             return $this->modFlag($mailbox, $messages, $flag, '-'); 
     1775        return $this->modFlag($mailbox, $messages, $flag, '-'); 
    17691776    } 
    17701777 
    17711778    function delete($mailbox, $messages) { 
    1772             return $this->modFlag($mailbox, $messages, 'DELETED', '+'); 
     1779        return $this->modFlag($mailbox, $messages, 'DELETED', '+'); 
    17731780    } 
    17741781 
    17751782    function copy($messages, $from, $to) 
    17761783    { 
    1777             if (!$this->select($from)) { 
    1778                 return false; 
    1779             } 
     1784        if (!$this->select($from)) { 
     1785            return false; 
     1786        } 
    17801787 
    17811788        // Clear internal status cache 
     
    17861793            self::COMMAND_NORESPONSE); 
    17871794 
    1788             return ($result == self::ERROR_OK); 
     1795        return ($result == self::ERROR_OK); 
    17891796    } 
    17901797 
    17911798    function move($messages, $from, $to) 
    17921799    { 
    1793             if (!$this->select($from)) { 
    1794                 return false; 
    1795             } 
     1800        if (!$this->select($from)) { 
     1801            return false; 
     1802        } 
    17961803 
    17971804        if (!$this->data['READ-WRITE']) { 
     
    18161823    private function parseThread($str, $begin, $end, $root, $parent, $depth, &$depthmap, &$haschildren) 
    18171824    { 
    1818             $node = array(); 
    1819             if ($str[$begin] != '(') { 
    1820                     $stop = $begin + strspn($str, '1234567890', $begin, $end - $begin); 
    1821                     $msg = substr($str, $begin, $stop - $begin); 
    1822                     if ($msg == 0) 
    1823                         return $node; 
    1824                     if (is_null($root)) 
    1825                             $root = $msg; 
    1826                     $depthmap[$msg] = $depth; 
    1827                     $haschildren[$msg] = false; 
    1828                     if (!is_null($parent)) 
    1829                             $haschildren[$parent] = true; 
    1830                     if ($stop + 1 < $end) 
    1831                             $node[$msg] = $this->parseThread($str, $stop + 1, $end, $root, $msg, $depth + 1, $depthmap, $haschildren); 
    1832                     else 
    1833                             $node[$msg] = array(); 
    1834             } else { 
    1835                     $off = $begin; 
    1836                     while ($off < $end) { 
    1837                             $start = $off; 
    1838                         $off++; 
    1839                         $n = 1; 
    1840                         while ($n > 0) { 
    1841                                 $p = strpos($str, ')', $off); 
    1842                                     if ($p === false) { 
    1843                                             error_log('Mismatched brackets parsing IMAP THREAD response:'); 
    1844                                         error_log(substr($str, ($begin < 10) ? 0 : ($begin - 10), $end - $begin + 20)); 
    1845                                         error_log(str_repeat(' ', $off - (($begin < 10) ? 0 : ($begin - 10)))); 
    1846                                         return $node; 
    1847                                 } 
    1848                                     $p1 = strpos($str, '(', $off); 
    1849                                 if ($p1 !== false && $p1 < $p) { 
    1850                                         $off = $p1 + 1; 
    1851                                         $n++; 
    1852                                 } else { 
    1853                                         $off = $p + 1; 
    1854                                             $n--; 
    1855                                 } 
    1856                         } 
    1857                         $node += $this->parseThread($str, $start + 1, $off - 1, $root, $parent, $depth, $depthmap, $haschildren); 
    1858                     } 
    1859             } 
    1860  
    1861             return $node; 
     1825        $node = array(); 
     1826        if ($str[$begin] != '(') { 
     1827            $stop = $begin + strspn($str, '1234567890', $begin, $end - $begin); 
     1828            $msg = substr($str, $begin, $stop - $begin); 
     1829            if ($msg == 0) 
     1830                return $node; 
     1831            if (is_null($root)) 
     1832                $root = $msg; 
     1833            $depthmap[$msg] = $depth; 
     1834            $haschildren[$msg] = false; 
     1835            if (!is_null($parent)) 
     1836                $haschildren[$parent] = true; 
     1837            if ($stop + 1 < $end) 
     1838                $node[$msg] = $this->parseThread($str, $stop + 1, $end, $root, $msg, $depth + 1, $depthmap, $haschildren); 
     1839            else 
     1840                $node[$msg] = array(); 
     1841        } else { 
     1842            $off = $begin; 
     1843            while ($off < $end) { 
     1844                $start = $off; 
     1845                $off++; 
     1846                $n = 1; 
     1847                while ($n > 0) { 
     1848                    $p = strpos($str, ')', $off); 
     1849                    if ($p === false) { 
     1850                        error_log("Mismatched brackets parsing IMAP THREAD response:"); 
     1851                        error_log(substr($str, ($begin < 10) ? 0 : ($begin - 10), $end - $begin + 20)); 
     1852                        error_log(str_repeat(' ', $off - (($begin < 10) ? 0 : ($begin - 10)))); 
     1853                        return $node; 
     1854                    } 
     1855                    $p1 = strpos($str, '(', $off); 
     1856                    if ($p1 !== false && $p1 < $p) { 
     1857                        $off = $p1 + 1; 
     1858                        $n++; 
     1859                    } else { 
     1860                        $off = $p + 1; 
     1861                        $n--; 
     1862                    } 
     1863                } 
     1864                $node += $this->parseThread($str, $start + 1, $off - 1, $root, $parent, $depth, $depthmap, $haschildren); 
     1865            } 
     1866        } 
     1867 
     1868        return $node; 
    18621869    } 
    18631870 
     
    18661873        $old_sel = $this->selected; 
    18671874 
    1868             if (!$this->select($mailbox)) { 
    1869                 return false; 
    1870             } 
     1875        if (!$this->select($mailbox)) { 
     1876            return false; 
     1877        } 
    18711878 
    18721879        // return empty result when folder is empty and we're just after SELECT 
    18731880        if ($old_sel != $mailbox && !$this->data['EXISTS']) { 
    18741881            return array(array(), array(), array()); 
    1875             } 
    1876  
    1877         $encoding  = $encoding ? trim($encoding) : 'US-ASCII'; 
    1878             $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES'; 
    1879             $criteria  = $criteria ? 'ALL '.trim($criteria) : 'ALL'; 
     1882        } 
     1883 
     1884        $encoding  = $encoding ? trim($encoding) : 'US-ASCII'; 
     1885        $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES'; 
     1886        $criteria  = $criteria ? 'ALL '.trim($criteria) : 'ALL'; 
    18801887        $data      = ''; 
    18811888 
     
    18831890            $algorithm, $encoding, $criteria)); 
    18841891 
    1885             if ($code == self::ERROR_OK && preg_match('/^\* THREAD /i', $response)) { 
    1886                 // remove prefix and \r\n from raw response 
    1887                 $response    = str_replace("\r\n", '', substr($response, 9)); 
     1892        if ($code == self::ERROR_OK && preg_match('/^\* THREAD /i', $response)) { 
     1893            // remove prefix and \r\n from raw response 
     1894            $response    = str_replace("\r\n", '', substr($response, 9)); 
    18881895            $depthmap    = array(); 
    18891896            $haschildren = array(); 
     
    18931900 
    18941901            return array($tree, $depthmap, $haschildren); 
    1895             } 
    1896  
    1897             return false; 
     1902        } 
     1903 
     1904        return false; 
    18981905    } 
    18991906 
     
    19121919        $old_sel = $this->selected; 
    19131920 
    1914             if (!$this->select($mailbox)) { 
    1915                 return false; 
    1916             } 
     1921        if (!$this->select($mailbox)) { 
     1922            return false; 
     1923        } 
    19171924 
    19181925        // return empty result when folder is empty and we're just after SELECT 
     
    19221929            else 
    19231930                return array(); 
    1924             } 
     1931        } 
    19251932 
    19261933        $esearch  = empty($items) ? false : $this->getCapability('ESEARCH'); 
     
    19391946        } 
    19401947 
    1941             list($code, $response) = $this->execute($return_uid ? 'UID SEARCH' : 'SEARCH', 
    1942                 array($params)); 
    1943  
    1944             if ($code == self::ERROR_OK) { 
    1945                 // remove prefix and \r\n from raw response 
     1948        list($code, $response) = $this->execute($return_uid ? 'UID SEARCH' : 'SEARCH', 
     1949            array($params)); 
     1950 
     1951        if ($code == self::ERROR_OK) { 
     1952            // remove prefix and \r\n from raw response 
    19461953            $response = substr($response, $esearch ? 10 : 9); 
    1947                 $response = str_replace("\r\n", '', $response); 
     1954            $response = str_replace("\r\n", '', $response); 
    19481955 
    19491956            if ($esearch) { 
     
    19631970                return $result; 
    19641971            } 
    1965                 else { 
     1972            else { 
    19661973                $response = preg_split('/\s+/', $response, -1, PREG_SPLIT_NO_EMPTY); 
    19671974 
    19681975                if (!empty($items)) { 
    19691976                    $result = array(); 
    1970                     if (in_array('COUNT', $items)) 
     1977                    if (in_array('COUNT', $items)) { 
    19711978                        $result['COUNT'] = count($response); 
    1972                     if (in_array('MIN', $items)) 
     1979                    } 
     1980                    if (in_array('MIN', $items)) { 
    19731981                        $result['MIN'] = !empty($response) ? min($response) : 0; 
    1974                     if (in_array('MAX', $items)) 
     1982                    } 
     1983                    if (in_array('MAX', $items)) { 
    19751984                        $result['MAX'] = !empty($response) ? max($response) : 0; 
    1976                     if (in_array('ALL', $items)) 
     1985                    } 
     1986                    if (in_array('ALL', $items)) { 
    19771987                        $result['ALL'] = $this->compressMessageSet($response, true); 
     1988                    } 
    19781989 
    19791990                    return $result; 
     
    19821993                    return $response; 
    19831994                } 
    1984                 } 
    1985         } 
    1986  
    1987             return false; 
     1995            } 
     1996        } 
     1997 
     1998        return false; 
    19881999    } 
    19892000 
     
    20392050        $status_opts=array(), $select_opts=array()) 
    20402051    { 
    2041                 if (!strlen($mailbox)) { 
    2042                 $mailbox = '*'; 
    2043             } 
     2052        if (!strlen($mailbox)) { 
     2053            $mailbox = '*'; 
     2054        } 
    20442055 
    20452056        $args = array(); 
     
    20732084                    // Add to result array 
    20742085                    if (!$lstatus) { 
    2075                                     $folders[] = $mailbox; 
     2086                        $folders[] = $mailbox; 
    20762087                    } 
    20772088                    else { 
     
    20972108                    } 
    20982109                } 
    2099                     } 
     2110            } 
    21002111 
    21012112            return $folders; 
    21022113        } 
    21032114 
    2104         return false; 
     2115        return false; 
    21052116    } 
    21062117 
    21072118    function fetchMIMEHeaders($mailbox, $id, $parts, $mime=true) 
    21082119    { 
    2109             if (!$this->select($mailbox)) { 
    2110                     return false; 
    2111             } 
    2112  
    2113         $result = false; 
    2114             $parts  = (array) $parts; 
    2115         $key    = $this->nextTag(); 
    2116             $peeks  = ''; 
    2117         $idx    = 0; 
     2120        if (!$this->select($mailbox)) { 
     2121            return false; 
     2122        } 
     2123 
     2124        $result = false; 
     2125        $parts  = (array) $parts; 
     2126        $key    = $this->nextTag(); 
     2127        $peeks  = ''; 
     2128        $idx    = 0; 
    21182129        $type   = $mime ? 'MIME' : 'HEADER'; 
    21192130 
    2120             // format request 
    2121             foreach($parts as $part) 
    2122                     $peeks[] = "BODY.PEEK[$part.$type]"; 
    2123  
    2124             $request = "$key FETCH $id (" . implode(' ', $peeks) . ')'; 
    2125  
    2126             // send request 
    2127             if (!$this->putLine($request)) { 
     2131        // format request 
     2132        foreach($parts as $part) { 
     2133            $peeks[] = "BODY.PEEK[$part.$type]"; 
     2134        } 
     2135 
     2136        $request = "$key FETCH $id (" . implode(' ', $peeks) . ')'; 
     2137 
     2138        // send request 
     2139        if (!$this->putLine($request)) { 
    21282140            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); 
    2129                 return false; 
    2130             } 
    2131  
    2132             do { 
    2133                 $line = $this->readLine(1024); 
    2134                 $line = $this->multLine($line); 
    2135  
    2136                     if (preg_match('/BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) { 
    2137                             $idx = $matches[1]; 
    2138                         $result[$idx] = preg_replace('/^(\* '.$id.' FETCH \()?\s*BODY\['.$idx.'\.'.$type.'\]\s+/', '', $line); 
    2139                         $result[$idx] = trim($result[$idx], '"'); 
    2140                         $result[$idx] = rtrim($result[$idx], "\t\r\n\0\x0B"); 
    2141                 } 
    2142             } while (!$this->startsWith($line, $key, true)); 
    2143  
    2144             return $result; 
     2141            return false; 
     2142        } 
     2143 
     2144        do { 
     2145            $line = $this->readLine(1024); 
     2146            $line = $this->multLine($line); 
     2147 
     2148            if (preg_match('/BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) { 
     2149                $idx = $matches[1]; 
     2150                $result[$idx] = preg_replace('/^(\* '.$id.' FETCH \()?\s*BODY\['.$idx.'\.'.$type.'\]\s+/', '', $line); 
     2151                $result[$idx] = trim($result[$idx], '"'); 
     2152                $result[$idx] = rtrim($result[$idx], "\t\r\n\0\x0B"); 
     2153            } 
     2154        } while (!$this->startsWith($line, $key, true)); 
     2155 
     2156        return $result; 
    21452157    } 
    21462158 
    21472159    function fetchPartHeader($mailbox, $id, $is_uid=false, $part=NULL) 
    21482160    { 
    2149             $part = empty($part) ? 'HEADER' : $part.'.MIME'; 
     2161        $part = empty($part) ? 'HEADER' : $part.'.MIME'; 
    21502162 
    21512163        return $this->handlePartBody($mailbox, $id, $is_uid, $part); 
     
    21542166    function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL) 
    21552167    { 
    2156         if (!$this->select($mailbox)) { 
    2157             return false; 
    2158         } 
    2159  
    2160             switch ($encoding) { 
    2161                     case 'base64': 
    2162                             $mode = 1; 
    2163                 break; 
    2164                 case 'quoted-printable': 
    2165                         $mode = 2; 
    2166                 break; 
    2167                 case 'x-uuencode': 
    2168                     case 'x-uue': 
    2169                 case 'uue': 
    2170                 case 'uuencode': 
    2171                         $mode = 3; 
    2172                 break; 
    2173                 default: 
    2174                         $mode = 0; 
    2175             } 
    2176  
    2177         // format request 
    2178                 $reply_key = '* ' . $id; 
    2179                 $key       = $this->nextTag(); 
    2180                 $request   = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])"; 
    2181  
    2182         // send request 
    2183                 if (!$this->putLine($request)) { 
     2168        if (!$this->select($mailbox)) { 
     2169            return false; 
     2170        } 
     2171 
     2172        switch ($encoding) { 
     2173        case 'base64': 
     2174            $mode = 1; 
     2175            break; 
     2176        case 'quoted-printable': 
     2177            $mode = 2; 
     2178            break; 
     2179        case 'x-uuencode': 
     2180        case 'x-uue': 
     2181        case 'uue': 
     2182        case 'uuencode': 
     2183            $mode = 3; 
     2184            break; 
     2185        default: 
     2186            $mode = 0; 
     2187        } 
     2188 
     2189        // format request 
     2190        $reply_key = '* ' . $id; 
     2191        $key       = $this->nextTag(); 
     2192        $request   = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])"; 
     2193 
     2194        // send request 
     2195        if (!$this->putLine($request)) { 
    21842196            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); 
    2185                     return false; 
    2186                 } 
    2187  
    2188                 // receive reply line 
    2189                 do { 
    2190                 $line = rtrim($this->readLine(1024)); 
    2191                 $a    = explode(' ', $line); 
    2192                 } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH'); 
    2193  
    2194                 $len    = strlen($line); 
    2195         $result = false; 
    2196  
    2197                 // handle empty "* X FETCH ()" response 
    2198         if ($line[$len-1] == ')' && $line[$len-2] != '(') { 
    2199                 // one line response, get everything between first and last quotes 
    2200                         if (substr($line, -4, 3) == 'NIL') { 
    2201                                 // NIL response 
    2202                                 $result = ''; 
    2203                         } else { 
    2204                             $from = strpos($line, '"') + 1; 
    2205                         $to   = strrpos($line, '"'); 
    2206                         $len  = $to - $from; 
    2207                                 $result = substr($line, $from, $len); 
    2208                         } 
    2209  
    2210                 if ($mode == 1) 
    2211                                 $result = base64_decode($result); 
    2212                         else if ($mode == 2) 
    2213                                 $result = quoted_printable_decode($result); 
    2214                         else if ($mode == 3) 
    2215                                 $result = convert_uudecode($result); 
    2216  
    2217         } else if ($line[$len-1] == '}') { 
    2218                 // multi-line request, find sizes of content and receive that many bytes 
    2219                 $from     = strpos($line, '{') + 1; 
    2220                 $to       = strrpos($line, '}'); 
    2221                 $len      = $to - $from; 
    2222                 $sizeStr  = substr($line, $from, $len); 
    2223                 $bytes    = (int)$sizeStr; 
    2224                         $prev     = ''; 
    2225  
    2226                 while ($bytes > 0) { 
    2227                     $line = $this->readLine(4096); 
    2228  
    2229                     if ($line === NULL) 
    2230                         break; 
    2231  
    2232                 $len  = strlen($line); 
    2233  
    2234                         if ($len > $bytes) { 
    2235                         $line = substr($line, 0, $bytes); 
    2236                                         $len = strlen($line); 
    2237                         } 
    2238                 $bytes -= $len; 
     2197            return false; 
     2198        } 
     2199 
     2200        // receive reply line 
     2201        do { 
     2202            $line = rtrim($this->readLine(1024)); 
     2203            $a    = explode(' ', $line); 
     2204        } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH'); 
     2205 
     2206        $len    = strlen($line); 
     2207        $result = false; 
     2208 
     2209        // handle empty "* X FETCH ()" response 
     2210        if ($line[$len-1] == ')' && $line[$len-2] != '(') { 
     2211            // one line response, get everything between first and last quotes 
     2212            if (substr($line, -4, 3) == 'NIL') { 
     2213                // NIL response 
     2214                $result = ''; 
     2215            } else { 
     2216                $from = strpos($line, '"') + 1; 
     2217                $to   = strrpos($line, '"'); 
     2218                $len  = $to - $from; 
     2219                $result = substr($line, $from, $len); 
     2220            } 
     2221 
     2222            if ($mode == 1) { 
     2223                $result = base64_decode($result); 
     2224            } 
     2225            else if ($mode == 2) { 
     2226                $result = quoted_printable_decode($result); 
     2227            } 
     2228            else if ($mode == 3) { 
     2229                $result = convert_uudecode($result); 
     2230            } 
     2231 
     2232        } else if ($line[$len-1] == '}') { 
     2233            // multi-line request, find sizes of content and receive that many bytes 
     2234            $from     = strpos($line, '{') + 1; 
     2235            $to       = strrpos($line, '}'); 
     2236            $len      = $to - $from; 
     2237            $sizeStr  = substr($line, $from, $len); 
     2238            $bytes    = (int)$sizeStr; 
     2239            $prev     = ''; 
     2240 
     2241            while ($bytes > 0) { 
     2242                $line = $this->readLine(4096); 
     2243 
     2244                if ($line === NULL) { 
     2245                    break; 
     2246                } 
     2247 
     2248                $len  = strlen($line); 
     2249 
     2250                if ($len > $bytes) { 
     2251                    $line = substr($line, 0, $bytes); 
     2252                    $len = strlen($line); 
     2253                } 
     2254                $bytes -= $len; 
    22392255 
    22402256                // BASE64 
    2241                         if ($mode == 1) { 
    2242                                         $line = rtrim($line, "\t\r\n\0\x0B"); 
    2243                                         // create chunks with proper length for base64 decoding 
    2244                                         $line = $prev.$line; 
    2245                                         $length = strlen($line); 
    2246                                         if ($length % 4) { 
    2247                                                 $length = floor($length / 4) * 4; 
    2248                                                 $prev = substr($line, $length); 
    2249                                                 $line = substr($line, 0, $length); 
    2250                                         } 
    2251                                         else 
    2252                                                 $prev = ''; 
    2253                                         $line = base64_decode($line); 
     2257                if ($mode == 1) { 
     2258                    $line = rtrim($line, "\t\r\n\0\x0B"); 
     2259                    // create chunks with proper length for base64 decoding 
     2260                    $line = $prev.$line; 
     2261                    $length = strlen($line); 
     2262                    if ($length % 4) { 
     2263                        $length = floor($length / 4) * 4; 
     2264                        $prev = substr($line, $length); 
     2265                        $line = substr($line, 0, $length); 
     2266                    } 
     2267                    else 
     2268                        $prev = ''; 
     2269                    $line = base64_decode($line); 
    22542270                // QUOTED-PRINTABLE 
    2255                                 } else if ($mode == 2) { 
    2256                                         $line = rtrim($line, "\t\r\0\x0B"); 
     2271                } else if ($mode == 2) { 
     2272                    $line = rtrim($line, "\t\r\0\x0B"); 
    22572273                    $line = quoted_printable_decode($line); 
    22582274                    // Remove NULL characters (#1486189) 
    22592275                    $line = str_replace("\x00", '', $line); 
    22602276                // UUENCODE 
    2261                                 } else if ($mode == 3) { 
    2262                                         $line = rtrim($line, "\t\r\n\0\x0B"); 
    2263                                         if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) 
    2264                                                 continue; 
     2277                } else if ($mode == 3) { 
     2278                    $line = rtrim($line, "\t\r\n\0\x0B"); 
     2279                    if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) 
     2280                        continue; 
    22652281                    $line = convert_uudecode($line); 
    22662282                // default 
    2267                                 } else { 
    2268                                         $line = rtrim($line, "\t\r\n\0\x0B") . "\n"; 
    2269                                 } 
    2270  
    2271                         if ($file) 
    2272                                         fwrite($file, $line); 
    2273                         else if ($print) 
    2274                                         echo $line; 
    2275                                 else 
    2276                                         $result .= $line; 
    2277                 } 
    2278         } 
     2283                } else { 
     2284                    $line = rtrim($line, "\t\r\n\0\x0B") . "\n"; 
     2285                } 
     2286 
     2287                if ($file) 
     2288                    fwrite($file, $line); 
     2289                else if ($print) 
     2290                    echo $line; 
     2291                else 
     2292                    $result .= $line; 
     2293            } 
     2294        } 
    22792295 
    22802296        // read in anything up until last line 
    2281                 if (!$end) 
    2282                         do { 
    2283                                 $line = $this->readLine(1024); 
    2284                         } while (!$this->startsWith($line, $key, true)); 
    2285  
    2286                 if ($result !== false) { 
    2287                 if ($file) { 
    2288                         fwrite($file, $result); 
    2289                         } else if ($print) { 
    2290                         echo $result; 
    2291                 } else 
    2292                         return $result; 
    2293                         return true; 
    2294                 } 
    2295  
    2296             return false; 
     2297        if (!$end) 
     2298            do { 
     2299                $line = $this->readLine(1024); 
     2300            } while (!$this->startsWith($line, $key, true)); 
     2301 
     2302        if ($result !== false) { 
     2303            if ($file) { 
     2304                fwrite($file, $result); 
     2305            } else if ($print) { 
     2306                echo $result; 
     2307            } else 
     2308                return $result; 
     2309            return true; 
     2310        } 
     2311 
     2312        return false; 
    22972313    } 
    22982314 
     
    23002316    { 
    23012317        $result = $this->execute('CREATE', array($this->escape($mailbox)), 
    2302                 self::COMMAND_NORESPONSE); 
    2303  
    2304             return ($result == self::ERROR_OK); 
     2318            self::COMMAND_NORESPONSE); 
     2319 
     2320        return ($result == self::ERROR_OK); 
    23052321    } 
    23062322 
     
    23082324    { 
    23092325        $result = $this->execute('RENAME', array($this->escape($from), $this->escape($to)), 
    2310                 self::COMMAND_NORESPONSE); 
    2311  
    2312                 return ($result == self::ERROR_OK); 
     2326            self::COMMAND_NORESPONSE); 
     2327 
     2328        return ($result == self::ERROR_OK); 
    23132329    } 
    23142330 
    23152331    function append($mailbox, &$message) 
    23162332    { 
    2317             if (!$mailbox) { 
    2318                     return false; 
    2319             } 
    2320  
    2321         $message = str_replace("\r", '', $message); 
    2322             $message = str_replace("\n", "\r\n", $message); 
    2323  
    2324         $len = strlen($message); 
    2325             if (!$len) { 
    2326                     return false; 
    2327             } 
     2333        if (!$mailbox) { 
     2334            return false; 
     2335        } 
     2336 
     2337        $message = str_replace("\r", '', $message); 
     2338        $message = str_replace("\n", "\r\n", $message); 
     2339 
     2340        $len = strlen($message); 
     2341        if (!$len) { 
     2342            return false; 
     2343        } 
    23282344 
    23292345        $key = $this->nextTag(); 
    2330             $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox), 
     2346        $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox), 
    23312347            $len, ($this->prefs['literal+'] ? '+' : '')); 
    23322348 
    2333             if ($this->putLine($request)) { 
     2349        if ($this->putLine($request)) { 
    23342350            // Don't wait when LITERAL+ is supported 
    23352351            if (!$this->prefs['literal+']) { 
    2336                 $line = $this->readLine(512); 
    2337  
    2338                     if ($line[0] != '+') { 
    2339                             $this->parseResult($line, 'APPEND: '); 
    2340                                 return false; 
    2341                     } 
    2342             } 
    2343  
    2344                 if (!$this->putLine($message)) { 
     2352                $line = $this->readReply(); 
     2353 
     2354                if ($line[0] != '+') { 
     2355                    $this->parseResult($line, 'APPEND: '); 
     2356                    return false; 
     2357                } 
     2358            } 
     2359 
     2360            if (!$this->putLine($message)) { 
    23452361                return false; 
    23462362            } 
    23472363 
    2348                     do { 
    2349                             $line = $this->readLine(); 
    2350                 } while (!$this->startsWith($line, $key, true, true)); 
     2364            do { 
     2365                $line = $this->readLine(); 
     2366            } while (!$this->startsWith($line, $key, true, true)); 
    23512367 
    23522368            // Clear internal status cache 
    23532369            unset($this->data['STATUS:'.$mailbox]); 
    23542370 
    2355                 return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK); 
    2356             } 
     2371            return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK); 
     2372        } 
    23572373        else { 
    23582374            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); 
    23592375        } 
    23602376 
    2361             return false; 
     2377        return false; 
    23622378    } 
    23632379 
    23642380    function appendFromFile($mailbox, $path, $headers=null) 
    23652381    { 
    2366             if (!$mailbox) { 
    2367                 return false; 
    2368             } 
    2369  
    2370             // open message file 
    2371             $in_fp = false; 
    2372             if (file_exists(realpath($path))) { 
    2373                     $in_fp = fopen($path, 'r'); 
    2374             } 
    2375             if (!$in_fp) { 
    2376                     $this->setError(self::ERROR_UNKNOWN, "Couldn't open $path for reading"); 
    2377                     return false; 
    2378             } 
     2382        if (!$mailbox) { 
     2383            return false; 
     2384        } 
     2385 
     2386        // open message file 
     2387        $in_fp = false; 
     2388        if (file_exists(realpath($path))) { 
     2389            $in_fp = fopen($path, 'r'); 
     2390        } 
     2391        if (!$in_fp) { 
     2392            $this->setError(self::ERROR_UNKNOWN, "Couldn't open $path for reading"); 
     2393            return false; 
     2394        } 
    23792395 
    23802396        $body_separator = "\r\n\r\n"; 
    2381             $len = filesize($path); 
    2382  
    2383             if (!$len) { 
    2384                     return false; 
    2385             } 
     2397        $len = filesize($path); 
     2398 
     2399        if (!$len) { 
     2400            return false; 
     2401        } 
    23862402 
    23872403        if ($headers) { 
     
    23902406        } 
    23912407 
    2392         // send APPEND command 
    2393         $key = $this->nextTag(); 
    2394             $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox), 
     2408        // send APPEND command 
     2409        $key = $this->nextTag(); 
     2410        $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox), 
    23952411            $len, ($this->prefs['literal+'] ? '+' : '')); 
    23962412 
    2397             if ($this->putLine($request)) { 
     2413        if ($this->putLine($request)) { 
    23982414            // Don't wait when LITERAL+ is supported 
    23992415            if (!$this->prefs['literal+']) { 
    2400                     $line = $this->readLine(512); 
    2401  
    2402                     if ($line[0] != '+') { 
    2403                             $this->parseResult($line, 'APPEND: '); 
    2404                                 return false; 
    2405                         } 
     2416                $line = $this->readReply(); 
     2417 
     2418                if ($line[0] != '+') { 
     2419                    $this->parseResult($line, 'APPEND: '); 
     2420                    return false; 
     2421                } 
    24062422            } 
    24072423 
    24082424            // send headers with body separator 
    24092425            if ($headers) { 
    2410                             $this->putLine($headers . $body_separator, false); 
    2411             } 
    2412  
    2413                     // send file 
    2414                     while (!feof($in_fp) && $this->fp) { 
    2415                             $buffer = fgets($in_fp, 4096); 
    2416                             $this->putLine($buffer, false); 
    2417                     } 
    2418                     fclose($in_fp); 
    2419  
    2420                     if (!$this->putLine('')) { // \r\n 
     2426                $this->putLine($headers . $body_separator, false); 
     2427            } 
     2428 
     2429            // send file 
     2430            while (!feof($in_fp) && $this->fp) { 
     2431                $buffer = fgets($in_fp, 4096); 
     2432                $this->putLine($buffer, false); 
     2433            } 
     2434            fclose($in_fp); 
     2435 
     2436            if (!$this->putLine('')) { // \r\n 
    24212437                return false; 
    24222438            } 
    24232439 
    2424                     // read response 
    2425                     do { 
    2426                             $line = $this->readLine(); 
    2427                     } while (!$this->startsWith($line, $key, true, true)); 
     2440            // read response 
     2441            do { 
     2442                $line = $this->readLine(); 
     2443            } while (!$this->startsWith($line, $key, true, true)); 
    24282444 
    24292445            // Clear internal status cache 
    24302446            unset($this->data['STATUS:'.$mailbox]); 
    24312447 
    2432                     return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK); 
    2433             } 
     2448            return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK); 
     2449        } 
    24342450        else { 
    24352451            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); 
    24362452        } 
    24372453 
    2438             return false; 
     2454        return false; 
    24392455    } 
    24402456 
    24412457    function fetchStructureString($mailbox, $id, $is_uid=false) 
    24422458    { 
    2443             if (!$this->select($mailbox)) { 
    2444             return false; 
    2445         } 
    2446  
    2447                 $key = $this->nextTag(); 
    2448         $result = false; 
     2459        if (!$this->select($mailbox)) { 
     2460            return false; 
     2461        } 
     2462 
     2463        $key = $this->nextTag(); 
     2464        $result = false; 
    24492465        $command = $key . ($is_uid ? ' UID' : '') ." FETCH $id (BODYSTRUCTURE)"; 
    24502466 
    2451                 if ($this->putLine($command)) { 
    2452                         do { 
    2453                                 $line = $this->readLine(5000); 
    2454                                 $line = $this->multLine($line, true); 
    2455                                 if (!preg_match("/^$key /", $line)) 
    2456                                         $result .= $line; 
    2457                         } while (!$this->startsWith($line, $key, true, true)); 
    2458  
    2459                         $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -1)); 
    2460                 } 
     2467        if ($this->putLine($command)) { 
     2468            do { 
     2469                $line = $this->readLine(5000); 
     2470                $line = $this->multLine($line, true); 
     2471                if (!preg_match("/^$key /", $line)) 
     2472                    $result .= $line; 
     2473            } while (!$this->startsWith($line, $key, true, true)); 
     2474 
     2475            $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -1)); 
     2476        } 
    24612477        else { 
    24622478            $this->setError(self::ERROR_COMMAND, "Unable to send command: $command"); 
    24632479        } 
    24642480 
    2465         return $result; 
     2481        return $result; 
    24662482    } 
    24672483 
     
    24742490         * OK Completed 
    24752491         */ 
    2476             $result      = false; 
    2477             $quota_lines = array(); 
    2478             $key         = $this->nextTag(); 
     2492        $result      = false; 
     2493        $quota_lines = array(); 
     2494        $key         = $this->nextTag(); 
    24792495        $command     = $key . ' GETQUOTAROOT INBOX'; 
    24802496 
    2481             // get line(s) containing quota info 
    2482             if ($this->putLine($command)) { 
    2483                     do { 
    2484                             $line = rtrim($this->readLine(5000)); 
    2485                             if (preg_match('/^\* QUOTA /', $line)) { 
    2486                                     $quota_lines[] = $line; 
    2487                         } 
    2488                     } while (!$this->startsWith($line, $key, true, true)); 
    2489             } 
     2497        // get line(s) containing quota info 
     2498        if ($this->putLine($command)) { 
     2499            do { 
     2500                $line = rtrim($this->readLine(5000)); 
     2501                if (preg_match('/^\* QUOTA /', $line)) { 
     2502                    $quota_lines[] = $line; 
     2503                } 
     2504            } while (!$this->startsWith($line, $key, true, true)); 
     2505        } 
    24902506        else { 
    24912507            $this->setError(self::ERROR_COMMAND, "Unable to send command: $command"); 
    24922508        } 
    24932509 
    2494             // return false if not found, parse if found 
    2495             $min_free = PHP_INT_MAX; 
    2496             foreach ($quota_lines as $key => $quota_line) { 
    2497                     $quota_line   = str_replace(array('(', ')'), '', $quota_line); 
    2498                     $parts        = explode(' ', $quota_line); 
    2499                     $storage_part = array_search('STORAGE', $parts); 
    2500  
    2501                     if (!$storage_part) 
     2510        // return false if not found, parse if found 
     2511        $min_free = PHP_INT_MAX; 
     2512        foreach ($quota_lines as $key => $quota_line) { 
     2513            $quota_line   = str_replace(array('(', ')'), '', $quota_line); 
     2514            $parts        = explode(' ', $quota_line); 
     2515            $storage_part = array_search('STORAGE', $parts); 
     2516 
     2517            if (!$storage_part) { 
    25022518                continue; 
    2503  
    2504                     $used  = intval($parts[$storage_part+1]); 
    2505                     $total = intval($parts[$storage_part+2]); 
    2506                     $free  = $total - $used; 
    2507  
    2508                     // return lowest available space from all quotas 
    2509                     if ($free < $min_free) { 
    2510                         $min_free          = $free; 
    2511                             $result['used']    = $used; 
    2512                             $result['total']   = $total; 
    2513                             $result['percent'] = min(100, round(($used/max(1,$total))*100)); 
    2514                             $result['free']    = 100 - $result['percent']; 
    2515                     } 
    2516             } 
    2517  
    2518             return $result; 
     2519            } 
     2520 
     2521            $used  = intval($parts[$storage_part+1]); 
     2522            $total = intval($parts[$storage_part+2]); 
     2523            $free  = $total - $used; 
     2524 
     2525            // return lowest available space from all quotas 
     2526            if ($free < $min_free) { 
     2527                $min_free          = $free; 
     2528                $result['used']    = $used; 
     2529                $result['total']   = $total; 
     2530                $result['percent'] = min(100, round(($used/max(1,$total))*100)); 
     2531                $result['free']    = 100 - $result['percent']; 
     2532            } 
     2533        } 
     2534 
     2535        return $result; 
    25192536    } 
    25202537 
     
    25412558            self::COMMAND_NORESPONSE); 
    25422559 
    2543             return ($result == self::ERROR_OK); 
     2560        return ($result == self::ERROR_OK); 
    25442561    } 
    25452562 
     
    25612578            self::COMMAND_NORESPONSE); 
    25622579 
    2563             return ($result == self::ERROR_OK); 
     2580        return ($result == self::ERROR_OK); 
    25642581    } 
    25652582 
     
    26812698 
    26822699        foreach ($entries as $name => $value) { 
    2683             if ($value === null) 
     2700            if ($value === null) { 
    26842701                $value = 'NIL'; 
    2685             else 
     2702            } 
     2703            else { 
    26862704                $value = sprintf("{%d}\r\n%s", strlen($value), $value); 
    2687  
     2705            } 
    26882706            $entries[$name] = $this->escape($name) . ' ' . $value; 
    26892707        } 
     
    27102728    function deleteMetadata($mailbox, $entries) 
    27112729    { 
    2712         if (!is_array($entries) && !empty($entries)) 
     2730        if (!is_array($entries) && !empty($entries)) { 
    27132731            $entries = explode(' ', $entries); 
     2732        } 
    27142733 
    27152734        if (empty($entries)) { 
     
    27182737        } 
    27192738 
    2720         foreach ($entries as $entry) 
     2739        foreach ($entries as $entry) { 
    27212740            $data[$entry] = NULL; 
     2741        } 
    27222742 
    27232743        return $this->setMetadata($mailbox, $data); 
     
    27552775            $opts = array(); 
    27562776 
    2757             if (!empty($options['MAXSIZE'])) 
     2777            if (!empty($options['MAXSIZE'])) { 
    27582778                $opts[] = 'MAXSIZE '.intval($options['MAXSIZE']); 
    2759             if (!empty($options['DEPTH'])) 
     2779            } 
     2780            if (!empty($options['DEPTH'])) { 
    27602781                $opts[] = 'DEPTH '.intval($options['DEPTH']); 
    2761  
    2762             if ($opts) 
     2782            } 
     2783 
     2784            if ($opts) { 
    27632785                $optlist = '(' . implode(' ', $opts) . ')'; 
     2786            } 
    27642787        } 
    27652788 
     
    28282851            $value = $entry[2]; 
    28292852 
    2830             if ($value === null) 
     2853            if ($value === null) { 
    28312854                $value = 'NIL'; 
    2832             else 
     2855            } 
     2856            else { 
    28332857                $value = sprintf("{%d}\r\n%s", strlen($value), $value); 
     2858            } 
    28342859 
    28352860            $entries[] = sprintf('%s (%s %s)', 
     
    29232948                            $attr  = $attribs[$x++]; 
    29242949                            $value = $attribs[$x++]; 
    2925                             if ($attr == 'value.priv') 
     2950                            if ($attr == 'value.priv') { 
    29262951                                $res['/private' . $entry] = $value; 
    2927                             else if ($attr == 'value.shared') 
     2952                            } 
     2953                            else if ($attr == 'value.shared') { 
    29282954                                $res['/shared' . $entry] = $value; 
     2955                            } 
    29292956                        } 
    29302957                    } 
     
    29743001        $response = $noresp ? null : ''; 
    29753002 
    2976         if (!empty($arguments)) 
     3003        if (!empty($arguments)) { 
    29773004            $query .= ' ' . implode(' ', $arguments); 
     3005        } 
    29783006 
    29793007        // Send command 
    2980             if (!$this->putLineC($query)) { 
     3008        if (!$this->putLineC($query)) { 
    29813009            $this->setError(self::ERROR_COMMAND, "Unable to send command: $query"); 
    2982                     return $noresp ? self::ERROR_COMMAND : array(self::ERROR_COMMAND, ''); 
    2983             } 
     3010            return $noresp ? self::ERROR_COMMAND : array(self::ERROR_COMMAND, ''); 
     3011        } 
    29843012 
    29853013        // Parse response 
    2986         do { 
    2987                 $line = $this->readLine(4096); 
    2988                 if ($response !== null) 
    2989                     $response .= $line; 
    2990         } while (!$this->startsWith($line, $tag . ' ', true, true)); 
    2991  
    2992             $code = $this->parseResult($line, $command . ': '); 
     3014        do { 
     3015            $line = $this->readLine(4096); 
     3016            if ($response !== null) { 
     3017                $response .= $line; 
     3018            } 
     3019        } while (!$this->startsWith($line, $tag . ' ', true, true)); 
     3020 
     3021        $code = $this->parseResult($line, $command . ': '); 
    29933022 
    29943023        // Remove last line from response 
    2995         if ($response) { 
    2996             $line_len = min(strlen($response), strlen($line) + 2); 
     3024        if ($response) { 
     3025            $line_len = min(strlen($response), strlen($line) + 2); 
    29973026            $response = substr($response, 0, -$line_len); 
    29983027        } 
    29993028 
    3000             // optional CAPABILITY response 
    3001             if (($options & self::COMMAND_CAPABILITY) && $code == self::ERROR_OK 
     3029        // optional CAPABILITY response 
     3030        if (($options & self::COMMAND_CAPABILITY) && $code == self::ERROR_OK 
    30023031            && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches) 
    30033032        ) { 
    3004                     $this->parseCapability($matches[1], true); 
    3005             } 
     3033            $this->parseCapability($matches[1], true); 
     3034        } 
    30063035 
    30073036        // return last line only (without command tag, result and response code) 
     
    30103039        } 
    30113040 
    3012             return $noresp ? $code : array($code, $response); 
     3041        return $noresp ? $code : array($code, $response); 
    30133042    } 
    30143043 
     
    30443073                // Advance the string 
    30453074                $str = substr($str, $epos + 3 + $bytes); 
    3046             break; 
     3075                break; 
    30473076 
    30483077            // Quoted string 
     
    30663095                $result[] = stripslashes(substr($str, 1, $pos - 1)); 
    30673096                $str      = substr($str, $pos + 1); 
    3068             break; 
     3097                break; 
    30693098 
    30703099            // Parenthesized list 
     
    30723101                $str = substr($str, 1); 
    30733102                $result[] = self::tokenizeResponse($str); 
    3074             break; 
     3103                break; 
    30753104            case ')': 
    30763105                $str = substr($str, 1); 
    30773106                return $result; 
    3078             break; 
     3107                break; 
    30793108 
    30803109            // String atom, number, NIL, *, % 
     
    30953124                    $str = substr($str, strlen($m[1])); 
    30963125                } 
    3097             break; 
     3126                break; 
    30983127            } 
    30993128        } 
     
    31043133    private function _xor($string, $string2) 
    31053134    { 
    3106             $result = ''; 
    3107             $size = strlen($string); 
    3108             for ($i=0; $i<$size; $i++) { 
    3109                 $result .= chr(ord($string[$i]) ^ ord($string2[$i])); 
    3110             } 
    3111             return $result; 
     3135        $result = ''; 
     3136        $size   = strlen($string); 
     3137 
     3138        for ($i=0; $i<$size; $i++) { 
     3139            $result .= chr(ord($string[$i]) ^ ord($string2[$i])); 
     3140        } 
     3141 
     3142        return $result; 
    31123143    } 
    31133144 
     
    31213152    private function strToTime($date) 
    31223153    { 
    3123             // support non-standard "GMTXXXX" literal 
    3124             $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); 
     3154        // support non-standard "GMTXXXX" literal 
     3155        $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); 
    31253156        // if date parsing fails, we have a date in non-rfc format. 
    3126             // remove token from the end and try again 
    3127             while ((($ts = @strtotime($date))===false) || ($ts < 0)) { 
    3128                 $d = explode(' ', $date); 
    3129                     array_pop($d); 
    3130                     if (!$d) break; 
    3131                     $date = implode(' ', $d); 
    3132             } 
    3133  
    3134             $ts = (int) $ts; 
    3135  
    3136             return $ts < 0 ? 0 : $ts; 
     3157        // remove token from the end and try again 
     3158        while ((($ts = @strtotime($date))===false) || ($ts < 0)) { 
     3159            $d = explode(' ', $date); 
     3160            array_pop($d); 
     3161            if (!$d) { 
     3162                break; 
     3163            } 
     3164            $date = implode(' ', $d); 
     3165        } 
     3166 
     3167        $ts = (int) $ts; 
     3168 
     3169        return $ts < 0 ? 0 : $ts; 
    31373170    } 
    31383171 
    31393172    private function splitHeaderLine($string) 
    31403173    { 
    3141             $pos = strpos($string, ':'); 
    3142             if ($pos>0) { 
    3143                     $res[0] = substr($string, 0, $pos); 
    3144                     $res[1] = trim(substr($string, $pos+1)); 
    3145                     return $res; 
    3146             } 
    3147         return $string; 
     3174        $pos = strpos($string, ':'); 
     3175        if ($pos>0) { 
     3176            $res[0] = substr($string, 0, $pos); 
     3177            $res[1] = trim(substr($string, $pos+1)); 
     3178            return $res; 
     3179        } 
     3180        return $string; 
    31483181    } 
    31493182 
     
    31733206    static function escape($string) 
    31743207    { 
    3175         // NIL 
    31763208        if ($string === null) { 
    31773209            return 'NIL'; 
    31783210        } 
    3179         // empty string 
    31803211        else if ($string === '') { 
    31813212            return '""'; 
    31823213        } 
    3183         // string: special chars: SP, CTL, (, ), {, %, *, ", \, ] 
    31843214        else if (preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5C\x5D\x7F]+)/', $string)) { 
    3185                 return '"' . strtr($string, array('"'=>'\\"', '\\' => '\\\\')) . '"'; 
     3215            // string: special chars: SP, CTL, (, ), {, %, *, ", \, ] 
     3216            return '"' . strtr($string, array('"'=>'\\"', '\\' => '\\\\')) . '"'; 
    31863217        } 
    31873218 
     
    31923223    static function unEscape($string) 
    31933224    { 
    3194             return strtr($string, array('\\"'=>'"', '\\\\' => '\\')); 
     3225        return strtr($string, array('\\"'=>'"', '\\\\' => '\\')); 
    31953226    } 
    31963227 
Note: See TracChangeset for help on using the changeset viewer.