Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   1  <?php
   2  /**
   3   * Copyright 2013-2017 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file LICENSE for license information (LGPL). If you
   6   * did not receive this file, see http://www.horde.org/licenses/lgpl21.
   7   *
   8   * @category  Horde
   9   * @copyright 2013-2017 Horde LLC
  10   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  11   * @package   Imap_Client
  12   */
  13  
  14  /**
  15   * PHP stream connection to the IMAP server.
  16   *
  17   * NOTE: This class is NOT intended to be accessed outside of the package.
  18   * There is NO guarantees that the API of this class will not change across
  19   * versions.
  20   *
  21   * @author    Michael Slusarz <slusarz@horde.org>
  22   * @category  Horde
  23   * @copyright 2013-2017 Horde LLC
  24   * @internal
  25   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  26   * @package   Imap_Client
  27   */
  28  class Horde_Imap_Client_Socket_Connection_Socket
  29  extends Horde_Imap_Client_Socket_Connection_Base
  30  {
  31      /**
  32       * If false, does not outpt the current line of client output to debug.
  33       *
  34       * @var boolean
  35       */
  36      public $client_debug = true;
  37  
  38      /**
  39       * Sending buffer.
  40       *
  41       * @var string
  42       */
  43      protected $_buffer = '';
  44  
  45      /**
  46       * Writes data to the IMAP output stream.
  47       *
  48       * @param string $data  String data.
  49       * @param boolean $eol  Append EOL?
  50       *
  51       * @throws Horde_Imap_Client_Exception
  52       */
  53      public function write($data, $eol = false)
  54      {
  55          if ($eol) {
  56              $buffer = $this->_buffer;
  57              $debug = $this->client_debug;
  58              $this->_buffer = '';
  59  
  60              $this->client_debug = true;
  61  
  62              if (fwrite($this->_stream, $buffer . $data . ($eol ? "\r\n" : '')) === false) {
  63                  throw new Horde_Imap_Client_Exception(
  64                      Horde_Imap_Client_Translation::r("Server write error."),
  65                      Horde_Imap_Client_Exception::SERVER_WRITEERROR
  66                  );
  67              }
  68  
  69              if ($debug) {
  70                  $this->_params['debug']->client($buffer . $data);
  71              }
  72          } else {
  73              $this->_buffer .= $data;
  74          }
  75      }
  76  
  77      /**
  78       * Writes literal data to the IMAP output stream.
  79       *
  80       * @param mixed $data      Either a stream resource, or Horde_Stream
  81       *                         object.
  82       * @param integer $length  The literal length.
  83       * @param boolean $binary  If true, this is binary data.
  84       *
  85       * @throws Horde_Imap_Client_Exception
  86       */
  87      public function writeLiteral($data, $length, $binary = false)
  88      {
  89          $this->_buffer = '';
  90          $success = false;
  91  
  92          if ($data instanceof Horde_Stream) {
  93              $data = $data->stream;
  94          }
  95  
  96          if (rewind($data)) {
  97              $success = true;
  98              while (!feof($data)) {
  99                  if ((($read_data = fread($data, 8192)) === false) ||
 100                      (fwrite($this->_stream, $read_data) === false)) {
 101                      $success = false;
 102                      break;
 103                  }
 104              }
 105          }
 106  
 107          if (!$success) {
 108              $this->client_debug = true;
 109              throw new Horde_Imap_Client_Exception(
 110                  Horde_Imap_Client_Translation::r("Server write error."),
 111                  Horde_Imap_Client_Exception::SERVER_WRITEERROR
 112              );
 113          }
 114  
 115          if ($this->client_debug && !empty($this->_params['debugliteral'])) {
 116              rewind($data);
 117              while (!feof($data)) {
 118                  $this->_params['debug']->raw(fread($data, 8192));
 119              }
 120          } else {
 121              $this->_params['debug']->client('[' . ($binary ? 'BINARY' : 'LITERAL') . ' DATA: ' . $length . ' bytes]');
 122          }
 123      }
 124  
 125      /**
 126       * Read data from incoming IMAP stream.
 127       *
 128       * @param integer $size  UNUSED: The number of bytes to read from the
 129       *                       socket.
 130       *
 131       * @return Horde_Imap_Client_Tokenize  The tokenized data.
 132       *
 133       * @throws Horde_Imap_Client_Exception
 134       */
 135      public function read($size = null)
 136      {
 137          $got_data = false;
 138          $literal_len = null;
 139          $token = new Horde_Imap_Client_Tokenize();
 140  
 141          do {
 142              if (feof($this->_stream)) {
 143                  $this->close();
 144                  $this->_params['debug']->info(
 145                      'ERROR: Server closed the connection.'
 146                  );
 147                  throw new Horde_Imap_Client_Exception(
 148                      Horde_Imap_Client_Translation::r("Mail server closed the connection unexpectedly."),
 149                      Horde_Imap_Client_Exception::DISCONNECT
 150                  );
 151              }
 152  
 153              if (is_null($literal_len)) {
 154                  $buffer = '';
 155  
 156                  while (($in = fgets($this->_stream)) !== false) {
 157                      $got_data = true;
 158  
 159                      if (substr($in, -1) === "\n") {
 160                          $in = rtrim($in);
 161                          $this->_params['debug']->server($buffer . $in);
 162                          $token->add($in);
 163                          break;
 164                      }
 165  
 166                      $buffer .= $in;
 167                      $token->add($in);
 168                  }
 169  
 170                  /* Check for literal data. */
 171                  if (is_null($len = $token->getLiteralLength())) {
 172                      break;
 173                  }
 174  
 175                  // Skip 0-length literal data.
 176                  if ($len['length']) {
 177                      $binary = $len['binary'];
 178                      $literal_len = $len['length'];
 179                  }
 180  
 181                  continue;
 182              }
 183  
 184              $old_len = $literal_len;
 185  
 186              while (($literal_len > 0) && !feof($this->_stream)) {
 187                  $in = fread($this->_stream, min($literal_len, 8192));
 188                  /* Only store in stream if this is something more than a
 189                   * nominal number of bytes. */
 190                  if ($old_len > 256) {
 191                      $token->addLiteralStream($in);
 192                  } else {
 193                      $token->add($in);
 194                  }
 195  
 196                  if (!empty($this->_params['debugliteral'])) {
 197                      $this->_params['debug']->raw($in);
 198                  }
 199  
 200                  $got_data = true;
 201                  $literal_len -= strlen($in);
 202              }
 203  
 204              $literal_len = null;
 205  
 206              if (empty($this->_params['debugliteral'])) {
 207                  $this->_params['debug']->server('[' . ($binary ? 'BINARY' : 'LITERAL') . ' DATA: ' . $old_len . ' bytes]');
 208              }
 209          } while (true);
 210  
 211          if (!$got_data) {
 212              $this->_params['debug']->info('ERROR: read/timeout error.');
 213              throw new Horde_Imap_Client_Exception(
 214                  Horde_Imap_Client_Translation::r("Error when communicating with the mail server."),
 215                  Horde_Imap_Client_Exception::SERVER_READERROR
 216              );
 217          }
 218  
 219          return $token;
 220      }
 221  
 222  }