[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/horde/framework/Horde/Imap/Client/Socket/ -> ClientSort.php (source)

   1  <?php
   2  /**
   3   * Copyright 2012-2014 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file COPYING 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 2012-2014 Horde LLC
  10   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  11   * @package   Imap_Client
  12   */
  13  
  14  /**
  15   * Client sorting methods for the Socket driver.
  16   *
  17   * NOTE: This class is NOT intended to be accessed outside of a Base object.
  18   * There is NO guarantees that the API of this class will not change across
  19   * versions.
  20   *
  21   * @author    Michael Slusarz <[email protected]>
  22   * @category  Horde
  23   * @copyright 2012-2014 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_ClientSort
  29  {
  30      /**
  31       * Socket object.
  32       *
  33       * @var Horde_Imap_Client_Socket
  34       */
  35      protected $_socket;
  36  
  37      /**
  38       * Constructor.
  39       *
  40       * @param Horde_Imap_Client_Socket $socket  Socket object.
  41       */
  42      public function __construct(Horde_Imap_Client_Socket $socket)
  43      {
  44          $this->_socket = $socket;
  45      }
  46  
  47      /**
  48       * Sort search results client side if the server does not support the SORT
  49       * IMAP extension (RFC 5256).
  50       *
  51       * @param Horde_Imap_Client_Ids $res  The search results.
  52       * @param array $opts                 The options to _search().
  53       *
  54       * @return array  The sort results.
  55       *
  56       * @throws Horde_Imap_Client_Exception
  57       */
  58      public function clientSort($res, $opts)
  59      {
  60          if (!count($res)) {
  61              return $res;
  62          }
  63  
  64          /* Generate the FETCH command needed. */
  65          $query = new Horde_Imap_Client_Fetch_Query();
  66  
  67          foreach ($opts['sort'] as $val) {
  68              switch ($val) {
  69              case Horde_Imap_Client::SORT_ARRIVAL:
  70                  $query->imapDate();
  71                  break;
  72  
  73              case Horde_Imap_Client::SORT_DATE:
  74                  $query->imapDate();
  75                  $query->envelope();
  76                  break;
  77  
  78              case Horde_Imap_Client::SORT_CC:
  79              case Horde_Imap_Client::SORT_DISPLAYFROM:
  80              case Horde_Imap_Client::SORT_DISPLAYTO:
  81              case Horde_Imap_Client::SORT_FROM:
  82              case Horde_Imap_Client::SORT_SUBJECT:
  83              case Horde_Imap_Client::SORT_TO:
  84                  $query->envelope();
  85                  break;
  86  
  87              case Horde_Imap_Client::SORT_SIZE:
  88                  $query->size();
  89                  break;
  90              }
  91          }
  92  
  93          if (!count($query)) {
  94              return $res;
  95          }
  96  
  97          $mbox = $this->_socket->currentMailbox();
  98          $fetch_res = $this->_socket->fetch($mbox['mailbox'], $query, array(
  99              'ids' => $res
 100          ));
 101  
 102          return $this->_clientSortProcess($res->ids, $fetch_res, $opts['sort']);
 103      }
 104  
 105      /**
 106       * If server does not support the THREAD IMAP extension (RFC 5256), do
 107       * ORDEREDSUBJECT threading on the client side.
 108       *
 109       * @param Horde_Imap_Client_Fetch_Results $data  Fetch results.
 110       * @param boolean $uids                          Are IDs UIDs?
 111       *
 112       * @return array  The thread sort results.
 113       */
 114      public function threadOrderedSubject(Horde_Imap_Client_Fetch_Results $data,
 115                                           $uids)
 116      {
 117          $dates = $this->_getSentDates($data, $data->ids());
 118          $out = $sorted = $tsort = array();
 119  
 120          foreach ($data as $k => $v) {
 121              $subject = strval(new Horde_Imap_Client_Data_BaseSubject($v->getEnvelope()->subject));
 122              $sorted[$subject][$k] = $dates[$k];
 123          }
 124  
 125          /* Step 1: Sort by base subject (already done).
 126           * Step 2: Sort by sent date within each thread. */
 127          foreach (array_keys($sorted) as $key) {
 128              asort($sorted[$key], SORT_NUMERIC);
 129              $tsort[$key] = reset($sorted[$key]);
 130          }
 131  
 132          /* Step 3: Sort by the sent date of the first message in the
 133           * thread. */
 134          asort($tsort, SORT_NUMERIC);
 135  
 136          /* Now, $tsort contains the order of the threads, and each thread
 137           * is sorted in $sorted. */
 138          foreach (array_keys($tsort) as $key) {
 139              $keys = array_keys($sorted[$key]);
 140              $out[$keys[0]] = array(
 141                  $keys[0] => 0
 142              ) + array_fill_keys(array_slice($keys, 1) , 1);
 143          }
 144  
 145          return new Horde_Imap_Client_Data_Thread($out, $uids ? 'uid' : 'sequence');
 146      }
 147  
 148      /**
 149       */
 150      protected function _clientSortProcess($res, $fetch_res, $sort)
 151      {
 152          /* The initial sort is on the entire set. */
 153          $slices = array(0 => $res);
 154          $reverse = false;
 155  
 156          foreach ($sort as $val) {
 157              if ($val == Horde_Imap_Client::SORT_REVERSE) {
 158                  $reverse = true;
 159                  continue;
 160              }
 161  
 162              $slices_list = $slices;
 163              $slices = array();
 164  
 165              foreach ($slices_list as $slice_start => $slice) {
 166                  $sorted = array();
 167  
 168                  if ($reverse) {
 169                      $slice = array_reverse($slice);
 170                  }
 171  
 172                  switch ($val) {
 173                  case Horde_Imap_Client::SORT_SEQUENCE:
 174                      /* There is no requirement that IDs be returned in
 175                       * sequence order (see RFC 4549 [4.3.1]). So we must sort
 176                       * ourselves. */
 177                      $sorted = array_flip($slice);
 178                      ksort($sorted, SORT_NUMERIC);
 179                      break;
 180  
 181                  case Horde_Imap_Client::SORT_SIZE:
 182                      foreach ($slice as $num) {
 183                          $sorted[$num] = $fetch_res[$num]->getSize();
 184                      }
 185                      asort($sorted, SORT_NUMERIC);
 186                      break;
 187  
 188                  case Horde_Imap_Client::SORT_DISPLAYFROM:
 189                  case Horde_Imap_Client::SORT_DISPLAYTO:
 190                      $field = ($val == Horde_Imap_Client::SORT_DISPLAYFROM)
 191                          ? 'from'
 192                          : 'to';
 193  
 194                      foreach ($slice as $num) {
 195                          $env = $fetch_res[$num]->getEnvelope();
 196  
 197                          if (empty($env->$field)) {
 198                              $sorted[$num] = null;
 199                          } else {
 200                              $addr_ob = reset($env->$field);
 201                              if (is_null($sorted[$num] = $addr_ob->personal)) {
 202                                  $sorted[$num] = $addr_ob->mailbox;
 203                              }
 204                          }
 205                      }
 206  
 207                      asort($sorted, SORT_LOCALE_STRING);
 208                      break;
 209  
 210                  case Horde_Imap_Client::SORT_CC:
 211                  case Horde_Imap_Client::SORT_FROM:
 212                  case Horde_Imap_Client::SORT_TO:
 213                      if ($val == Horde_Imap_Client::SORT_CC) {
 214                          $field = 'cc';
 215                      } elseif ($val == Horde_Imap_Client::SORT_FROM) {
 216                          $field = 'from';
 217                      } else {
 218                          $field = 'to';
 219                      }
 220  
 221                      foreach ($slice as $num) {
 222                          $tmp = $fetch_res[$num]->getEnvelope()->$field;
 223                          $sorted[$num] = count($tmp)
 224                              ? $tmp[0]->mailbox
 225                              : null;
 226                      }
 227                      asort($sorted, SORT_LOCALE_STRING);
 228                      break;
 229  
 230                  case Horde_Imap_Client::SORT_ARRIVAL:
 231                      $sorted = $this->_getSentDates($fetch_res, $slice, true);
 232                      asort($sorted, SORT_NUMERIC);
 233                      break;
 234  
 235                  case Horde_Imap_Client::SORT_DATE:
 236                      // Date sorting rules in RFC 5256 [2.2]
 237                      $sorted = $this->_getSentDates($fetch_res, $slice);
 238                      asort($sorted, SORT_NUMERIC);
 239                      break;
 240  
 241                  case Horde_Imap_Client::SORT_SUBJECT:
 242                      // Subject sorting rules in RFC 5256 [2.1]
 243                      foreach ($slice as $num) {
 244                          $sorted[$num] = strval(new Horde_Imap_Client_Data_BaseSubject($fetch_res[$num]->getEnvelope()->subject));
 245                      }
 246                      asort($sorted, SORT_LOCALE_STRING);
 247                      break;
 248                  }
 249  
 250                  // At this point, keys of $sorted are sequence/UID and values
 251                  // are the sort strings
 252                  if (!empty($sorted)) {
 253                      if (count($sorted) === count($res)) {
 254                          $res = array_keys($sorted);
 255                      } else {
 256                          array_splice($res, $slice_start, count($slice), array_keys($sorted));
 257                      }
 258  
 259                      // Check for ties.
 260                      $last = $start = null;
 261                      $i = 0;
 262                      reset($sorted);
 263                      while (list($k, $v) = each($sorted)) {
 264                          if (is_null($last) || ($last != $v)) {
 265                              if ($i) {
 266                                  $slices[array_search($start, $res)] = array_slice($sorted, array_search($start, $sorted), $i + 1);
 267                                  $i = 0;
 268                              }
 269                              $last = $v;
 270                              $start = $k;
 271                          } else {
 272                              ++$i;
 273                          }
 274                      }
 275                      if ($i) {
 276                          $slices[array_search($start, $res)] = array_slice($sorted, array_search($start, $sorted), $i + 1);
 277                      }
 278                  }
 279              }
 280  
 281              $reverse = false;
 282          }
 283  
 284          return $res;
 285      }
 286  
 287      /**
 288       * Get the sent dates for purposes of SORT/THREAD sorting under RFC 5256
 289       * [2.2].
 290       *
 291       * @param Horde_Imap_Client_Fetch_Results $data  Data returned from
 292       *                                               fetch() that includes
 293       *                                               both date and envelope
 294       *                                               items.
 295       * @param array $ids                             The IDs to process.
 296       * @param boolean $internal                      Only use internal date?
 297       *
 298       * @return array  A mapping of IDs -> UNIX timestamps.
 299       */
 300      protected function _getSentDates(Horde_Imap_Client_Fetch_Results $data,
 301                                       $ids, $internal = false)
 302      {
 303          $dates = array();
 304  
 305          foreach ($ids as $num) {
 306              $dt = ($internal || !isset($data[$num]->getEnvelope()->date))
 307                  // RFC 5256 [3] & 3501 [6.4.4]: disregard timezone when
 308                  // using internaldate.
 309                  ? $data[$num]->getImapDate()
 310                  : $data[$num]->getEnvelope()->date;
 311              $dates[$num] = $dt->format('U');
 312          }
 313  
 314          return $dates;
 315      }
 316  
 317  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1