alecpl
2010-10-14 8fcc3e1ad67496496c788023daeb01631a39d915
program/include/rcube_imap_generic.php
@@ -112,6 +112,13 @@
   private $capability_readed = false;
    private $prefs;
    const ERROR_OK = 0;
    const ERROR_NO = -1;
    const ERROR_BAD = -2;
    const ERROR_BYE = -3;
    const ERROR_COMMAND = -5;
    const ERROR_UNKNOWN = -4;
    /**
     * Object constructor
     */
@@ -264,24 +271,36 @@
       return $line;
    }
    function parseResult($string)
    function parseResult($string, $err_prefix='')
    {
       $a = explode(' ', trim($string));
       if (count($a) >= 2) {
          $res = strtoupper($a[1]);
       if (preg_match('/^[a-z0-9*]+ (OK|NO|BAD|BYE)(.*)$/i', trim($string), $matches)) {
          $res = strtoupper($matches[1]);
            $str = trim($matches[2]);
          if ($res == 'OK') {
             return 0;
             return self::ERROR_OK;
          } else if ($res == 'NO') {
             return -1;
                $this->errornum = self::ERROR_NO;
          } else if ($res == 'BAD') {
             return -2;
             $this->errornum = self::ERROR_BAD;
          } else if ($res == 'BYE') {
                @fclose($this->fp);
                $this->fp = null;
             return -3;
             $this->errornum = self::ERROR_BYE;
          }
            if ($str)
                $this->error = $err_prefix ? $err_prefix.$str : $str;
           return $this->errornum;
       }
       return -4;
       return self::ERROR_UNKNOWN;
    }
    private function set_error($code, $msg='')
    {
        $this->errornum = $code;
        $this->error    = $msg;
    }
    // check if $string starts with $match (or * BYE/BAD)
@@ -377,13 +396,11 @@
        // process result
        $result = $this->parseResult($line);
        if ($result == 0) {
            $this->errornum = 0;
        if ($result == self::ERROR_OK) {
            return $this->fp;
        }
        $this->error    = "Authentication for $user failed (AUTH): $line";
        $this->errornum = $result;
        return $result;
    }
@@ -402,16 +419,13 @@
        // process result
        $result = $this->parseResult($line);
        if ($result == 0) {
            $this->errornum = 0;
        if ($result == self::ERROR_OK) {
            return $this->fp;
        }
        @fclose($this->fp);
        $this->fp = false;
        $this->error    = "Authentication for $user failed (LOGIN): $line";
        $this->errornum = $result;
        return $result;
    }
@@ -550,7 +564,7 @@
       // initialize connection
       $this->error    = '';
       $this->errornum = 0;
       $this->errornum = self::ERROR_OK;
       $this->selected = '';
       $this->user     = $user;
       $this->host     = $host;
@@ -558,18 +572,15 @@
       // check input
       if (empty($host)) {
          $this->error    = "Empty host";
          $this->errornum = -2;
          $this->set_error(self::ERROR_BAD, "Empty host");
          return false;
       }
        if (empty($user)) {
          $this->error    = "Empty user";
          $this->errornum = -1;
          $this->set_error(self::ERROR_NO, "Empty user");
          return false;
       }
       if (empty($password)) {
          $this->error    = "Empty password";
          $this->errornum = -1;
          $this->set_error(self::ERROR_NO, "Empty password");
          return false;
       }
@@ -588,8 +599,7 @@
           $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr);
       if (!$this->fp) {
          $this->error    = sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr);
          $this->errornum = -2;
          $this->set_error(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr));
          return false;
       }
@@ -608,7 +618,7 @@
             $this->error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line);
          else
             $this->error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']);
           $this->errornum = -2;
           $this->errornum = self::ERROR_BAD;
           return false;
       }
@@ -626,14 +636,12 @@
             $line = $this->readLine(4096);
                if (!preg_match('/^tls0 OK/', $line)) {
                $this->error    = "Server responded to STARTTLS with: $line";
                $this->errornum = -2;
                $this->set_error(self::ERROR_BAD, "Server responded to STARTTLS with: $line");
                    return false;
                }
             if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                $this->error    = "Unable to negotiate TLS";
                $this->errornum = -2;
                $this->set_error(self::ERROR_BAD, "Unable to negotiate TLS");
                return false;
             }
@@ -665,7 +673,7 @@
             $result = $this->authenticate($user, $password, substr($line,2));
             // stop if server sent BYE response
             if ($result == -3) {
             if ($result == self::ERROR_BYE) {
                return false;
             }
          }
@@ -717,7 +725,13 @@
          return true;
       }
       if ($this->putLine("sel1 SELECT \"".$this->escape($mailbox).'"')) {
        $command = "sel1 SELECT \"".$this->escape($mailbox).'"';
       if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return false;
        }
          do {
             $line = rtrim($this->readLine(512));
@@ -730,13 +744,11 @@
             }
          } while (!$this->startsWith($line, 'sel1', true, true));
            if ($this->parseResult($line) == 0) {
        if ($this->parseResult($line, 'SELECT: ') == self::ERROR_OK) {
             $this->selected = $mailbox;
             return true;
          }
       }
        $this->error = "Couldn't select $mailbox";
        return false;
    }
@@ -801,6 +813,7 @@
           $command .= ' '.$add;
       if (!$this->putLineC($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
           return false;
       }
       do {
@@ -812,9 +825,8 @@
          }
       } while (!$this->startsWith($line, 's ', true, true));
       $result_code = $this->parseResult($line);
       if ($result_code != 0) {
            $this->error = "Sort: $line";
       $result_code = $this->parseResult($line, 'SORT: ');
       if ($result_code != self::ERROR_OK) {
            return false;
       }
@@ -882,6 +894,7 @@
       $request = $key . $request;
       if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
          return false;
        }
@@ -1015,14 +1028,19 @@
        }
       $result = -1;
      if ($this->putLine("fuid FETCH $id (UID)")) {
        $command = "fuid FETCH $id (UID)";
      if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return -1;
        }
          do {
             $line = rtrim($this->readLine(1024));
            if (preg_match("/^\* $id FETCH \(UID (.*)\)/i", $line, $r)) {
               $result = $r[1];
            }
         } while (!$this->startsWith($line, 'fuid', true, true));
      }
       return $result;
    }
@@ -1063,6 +1081,7 @@
       $request .= "LIST-POST DISPOSITION-NOTIFICATION-TO".$add.")])";
       if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
          return false;
       }
       do {
@@ -1368,9 +1387,10 @@
        }
        $c = 0;
      $command = $messages ? "UID EXPUNGE $messages" : "EXPUNGE";
      $command = $messages ? "exp1 UID EXPUNGE $messages" : "exp1 EXPUNGE";
      if (!$this->putLine("exp1 $command")) {
      if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return -1;
        }
@@ -1381,11 +1401,11 @@
           }
      } while (!$this->startsWith($line, 'exp1', true, true));
      if ($this->parseResult($line) == 0) {
      if ($this->parseResult($line, 'EXPUNGE: ') == self::ERROR_OK) {
         $this->selected = ''; // state has changed, need to reselect
         return $c;
      }
      $this->error = $line;
       return -1;
    }
@@ -1402,7 +1422,9 @@
       }
        $c = 0;
       if (!$this->putLine("flg UID STORE $messages {$mod}FLAGS ($flag)")) {
        $command = "flg UID STORE $messages {$mod}FLAGS ($flag)";
       if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return false;
        }
@@ -1413,11 +1435,10 @@
            }
       } while (!$this->startsWith($line, 'flg', true, true));
       if ($this->parseResult($line) == 0) {
       if ($this->parseResult($line, 'STORE: ') == self::ERROR_OK) {
          return $c;
       }
       $this->error = $line;
       return -1;
    }
@@ -1443,9 +1464,14 @@
            return -1;
       }
        $this->putLine("cpy1 UID COPY $messages \"".$this->escape($to)."\"");
        $command = "cpy1 UID COPY $messages \"".$this->escape($to)."\"";
        if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
        }
       $line = $this->readReply();
       return $this->parseResult($line);
       return $this->parseResult($line, 'COPY: ');
    }
    function countUnseen($folder)
@@ -1525,7 +1551,10 @@
       $criteria  = $criteria ? 'ALL '.trim($criteria) : 'ALL';
        $data      = '';
       if (!$this->putLineC("thrd1 THREAD $algorithm $encoding $criteria")) {
        $command = "thrd1 THREAD $algorithm $encoding $criteria";
       if (!$this->putLineC($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
          return false;
       }
       do {
@@ -1537,15 +1566,14 @@
          }
       } while (!$this->startsWith($line, 'thrd1', true, true));
       $result_code = $this->parseResult($line);
       if ($result_code == 0) {
       $result_code = $this->parseResult($line, 'THREAD: ');
       if ($result_code == self::ERROR_OK) {
            $depthmap    = array();
            $haschildren = array();
            $tree = $this->parseThread($data, 0, strlen($data), null, null, 0, $depthmap, $haschildren);
            return array($tree, $depthmap, $haschildren);
       }
       $this->error = "Thread: $line";
       return false;
    }
@@ -1566,6 +1594,7 @@
       $query = 'srch1 ' . ($return_uid ? 'UID ' : '') . 'SEARCH ' . trim($criteria);
       if (!$this->putLineC($query)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $query");
          return false;
       }
@@ -1578,12 +1607,11 @@
          }
       } while (!$this->startsWith($line, 'srch1', true, true));
       $result_code = $this->parseResult($line);
       if ($result_code == 0) {
       $result_code = $this->parseResult($line, 'SEARCH: ');
       if ($result_code == self::ERROR_OK) {
          return preg_split('/\s+/', $data, -1, PREG_SPLIT_NO_EMPTY);
       }
       $this->error = "Search: $line";
       return false;
    }
@@ -1632,10 +1660,11 @@
        $ref = $this->escape($ref);
        $mailbox = $this->escape($mailbox);
        $query = $key." ".$command." \"". $ref ."\" \"". $mailbox ."\"";
       // send command
       if (!$this->putLine($key." ".$command." \"". $ref ."\" \"". $mailbox ."\"")) {
          $this->error = "Couldn't send $command command";
       if (!$this->putLine($query)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $query");
           return false;
       }
@@ -1657,11 +1686,10 @@
       if (is_array($folders)) {
           return $folders;
       } else if ($this->parseResult($line) == 0) {
       } else if ($this->parseResult($line, $command.': ') == self::ERROR_OK) {
            return array();
        }
       $this->error = $line;
       return false;
    }
@@ -1686,6 +1714,7 @@
       // send request
       if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
           return false;
       }
@@ -1741,6 +1770,7 @@
       // send request
      if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
          return false;
         }
@@ -1866,35 +1896,48 @@
    function createFolder($folder)
    {
       if ($this->putLine('c CREATE "' . $this->escape($folder) . '"')) {
        $command = 'c CREATE "' . $this->escape($folder) . '"';
       if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return false;
        }
          do {
             $line = $this->readLine(300);
          } while (!$this->startsWith($line, 'c ', true, true));
          return ($this->parseResult($line) == 0);
       }
       return false;
       return ($this->parseResult($line, 'CREATE: ') == self::ERROR_OK);
    }
    function renameFolder($from, $to)
    {
       if ($this->putLine('r RENAME "' . $this->escape($from) . '" "' . $this->escape($to) . '"')) {
        $command = 'r RENAME "' . $this->escape($from) . '" "' . $this->escape($to) . '"';
       if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return false;
        }
          do {
             $line = $this->readLine(300);
          } while (!$this->startsWith($line, 'r ', true, true));
          return ($this->parseResult($line) == 0);
       }
       return false;
      return ($this->parseResult($line, 'RENAME: ') == self::ERROR_OK);
    }
    function deleteFolder($folder)
    {
       if ($this->putLine('d DELETE "' . $this->escape($folder). '"')) {
        $command = 'd DELETE "' . $this->escape($folder). '"';
       if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return false;
        }
          do {
             $line = $this->readLine(300);
          } while (!$this->startsWith($line, 'd ', true, true));
          return ($this->parseResult($line) == 0);
       }
       return false;
       return ($this->parseResult($line, 'DELETE: ') == self::ERROR_OK);
    }
    function clearFolder($folder)
@@ -1908,20 +1951,28 @@
    function subscribe($folder)
    {
       $query = 'sub1 SUBSCRIBE "' . $this->escape($folder). '"';
       $this->putLine($query);
       $command = 'sub1 SUBSCRIBE "' . $this->escape($folder). '"';
       if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return false;
        }
       $line = trim($this->readLine(512));
       return ($this->parseResult($line) == 0);
       return ($this->parseResult($line, 'SUBSCRIBE: ') == self::ERROR_OK);
    }
    function unsubscribe($folder)
    {
        $query = 'usub1 UNSUBSCRIBE "' . $this->escape($folder) . '"';
       $this->putLine($query);
        $command = 'usub1 UNSUBSCRIBE "' . $this->escape($folder) . '"';
       if (!$this->putLine($command)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            return false;
        }
       $line = trim($this->readLine(512));
       return ($this->parseResult($line) == 0);
       return ($this->parseResult($line, 'UNSUBSCRIBE: ') == self::ERROR_OK);
    }
    function append($folder, &$message)
@@ -1944,8 +1995,7 @@
          $line = $this->readLine(512);
          if ($line[0] != '+') {
             // $errornum = $this->parseResult($line);
             $this->error = "Cannot write to folder: $line";
             $this->parseResult($line, 'APPEND: ');
             return false;
          }
@@ -1957,14 +2007,12 @@
             $line = $this->readLine();
          } while (!$this->startsWith($line, 'a ', true, true));
          $result = ($this->parseResult($line) == 0);
          if (!$result) {
              $this->error = $line;
          return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK);
          }
          return $result;
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
       }
       $this->error = "Couldn't send command \"$request\"";
       return false;
    }
@@ -1980,7 +2028,7 @@
          $in_fp = fopen($path, 'r');
       }
       if (!$in_fp) {
          $this->error = "Couldn't open $path for reading";
          $this->set_error(self::ERROR_UNKNOWN, "Couldn't open $path for reading");
          return false;
       }
@@ -2002,8 +2050,7 @@
          $line = $this->readLine(512);
          if ($line[0] != '+') {
             //$errornum = $this->parseResult($line);
             $this->error = "Cannot write to folder: $line";
             $this->parseResult($line, 'APPEND: ');
             return false;
          }
@@ -2028,15 +2075,13 @@
             $line = $this->readLine();
          } while (!$this->startsWith($line, 'a ', true, true));
          $result = ($this->parseResult($line) == 0);
          if (!$result) {
              $this->error = $line;
          return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK);
       }
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
          }
          return $result;
       }
       $this->error = "Couldn't send command \"$request\"";
       return false;
    }
@@ -2048,8 +2093,9 @@
      $key = 'F1247';
       $result = false;
        $command = $key . ($is_uid ? ' UID' : '') ." FETCH $id (BODYSTRUCTURE)";
      if ($this->putLine($key . ($is_uid ? ' UID' : '') ." FETCH $id (BODYSTRUCTURE)")) {
      if ($this->putLine($command)) {
         do {
            $line = $this->readLine(5000);
            $line = $this->multLine($line, true);
@@ -2058,6 +2104,9 @@
         } while (!$this->startsWith($line, $key, true, true));
         $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -1));
      }
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
      }
       return $result;
@@ -2073,9 +2122,10 @@
         */
       $result      = false;
       $quota_lines = array();
        $command     = 'QUOT1 GETQUOTAROOT "INBOX"';
       // get line(s) containing quota info
       if ($this->putLine('QUOT1 GETQUOTAROOT "INBOX"')) {
       if ($this->putLine($command)) {
          do {
             $line = rtrim($this->readLine(5000));
             if (preg_match('/^\* QUOTA /', $line)) {
@@ -2083,6 +2133,9 @@
              }
          } while (!$this->startsWith($line, 'QUOT1', true, true));
       }
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
        }
       // return false if not found, parse if found
       $min_free = PHP_INT_MAX;