[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/horde/framework/Horde/Mail/Rfc822/ -> List.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 (BSD). If you
   6   * did not receive this file, see http://www.horde.org/licenses/bsd.
   7   *
   8   * @category  Horde
   9   * @copyright 2012-2014 Horde LLC
  10   * @license   http://www.horde.org/licenses/bsd New BSD License
  11   * @package   Mail
  12   */
  13  
  14  /**
  15   * Container object for a collection of RFC 822 elements.
  16   *
  17   * @author    Michael Slusarz <slusarz@horde.org>
  18   * @category  Horde
  19   * @copyright 2012-2014 Horde LLC
  20   * @license   http://www.horde.org/licenses/bsd New BSD License
  21   * @package   Mail
  22   *
  23   * @property-read array $addresses  The list of all addresses (address
  24   *                                  w/personal parts).
  25   * @property-read array $bare_addresses  The list of all addresses (mail@host).
  26   * @property-read array $bare_addresses_idn  The list of all addresses
  27   *                                           (mail@host; IDN encoded).
  28   *                                           (@since 2.1.0)
  29   * @property-read array $base_addresses  The list of ONLY base addresses
  30   *                                       (Address objects).
  31   * @property-read array $raw_addresses  The list of all addresses (Address
  32   *                                      objects).
  33   */
  34  class Horde_Mail_Rfc822_List extends Horde_Mail_Rfc822_Object implements ArrayAccess, Countable, SeekableIterator, Serializable
  35  {
  36      /** Filter masks. */
  37      const HIDE_GROUPS = 1;
  38      const BASE_ELEMENTS = 2;
  39  
  40      /**
  41       * List data.
  42       *
  43       * @var array
  44       */
  45      protected $_data = array();
  46  
  47      /**
  48       * Current Iterator filter.
  49       *
  50       * @var array
  51       */
  52      protected $_filter = array();
  53  
  54      /**
  55       * Current Iterator pointer.
  56       *
  57       * @var array
  58       */
  59      protected $_ptr;
  60  
  61      /**
  62       * Constructor.
  63       *
  64       * @param mixed $obs  Address data to store in this object.
  65       */
  66      public function __construct($obs = null)
  67      {
  68          if (!is_null($obs)) {
  69              $this->add($obs);
  70          }
  71      }
  72  
  73      /**
  74       */
  75      public function __get($name)
  76      {
  77          switch ($name) {
  78          case 'addresses':
  79          case 'bare_addresses':
  80          case 'bare_addresses_idn':
  81          case 'base_addresses':
  82          case 'raw_addresses':
  83              $old = $this->_filter;
  84              $mask = ($name == 'base_addresses')
  85                  ? self::BASE_ELEMENTS
  86                  : self::HIDE_GROUPS;
  87              $this->setIteratorFilter($mask, empty($old['filter']) ? null : $old['filter']);
  88  
  89              $out = array();
  90              foreach ($this as $val) {
  91                  switch ($name) {
  92                  case 'addresses':
  93                      $out[] = strval($val);
  94                      break;
  95  
  96                  case 'bare_addresses':
  97                      $out[] = $val->bare_address;
  98                      break;
  99  
 100                  case 'bare_addresses_idn':
 101                      $out[] = $val->bare_address_idn;
 102                      break;
 103  
 104                  case 'base_addresses':
 105                  case 'raw_addresses':
 106                      $out[] = clone $val;
 107                      break;
 108                  }
 109              }
 110  
 111              $this->_filter = $old;
 112              return $out;
 113          }
 114      }
 115  
 116      /**
 117       * Add objects to the container.
 118       *
 119       * @param mixed $obs  Address data to store in this object.
 120       */
 121      public function add($obs)
 122      {
 123          foreach ($this->_normalize($obs) as $val) {
 124              $this->_data[] = $val;
 125          }
 126      }
 127  
 128      /**
 129       * Remove addresses from the container. This method ignores Group objects.
 130       *
 131       * @param mixed $obs  Addresses to remove.
 132       */
 133      public function remove($obs)
 134      {
 135          $old = $this->_filter;
 136          $this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS);
 137  
 138          foreach ($this->_normalize($obs) as $val) {
 139              $remove = array();
 140  
 141              foreach ($this as $key => $val2) {
 142                  if ($val2->match($val)) {
 143                      $remove[] = $key;
 144                  }
 145              }
 146  
 147              foreach (array_reverse($remove) as $key) {
 148                  unset($this[$key]);
 149              }
 150          }
 151  
 152          $this->_filter = $old;
 153      }
 154  
 155      /**
 156       * Removes duplicate addresses from list. This method ignores Group
 157       * objects.
 158       */
 159      public function unique()
 160      {
 161          $exist = $remove = array();
 162  
 163          $old = $this->_filter;
 164          $this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS);
 165  
 166          // For duplicates, we use the first address that contains personal
 167          // information.
 168          foreach ($this as $key => $val) {
 169              $bare = $val->bare_address;
 170              if (isset($exist[$bare])) {
 171                  if (($exist[$bare] == -1) || is_null($val->personal)) {
 172                      $remove[] = $key;
 173                  } else {
 174                      $remove[] = $exist[$bare];
 175                      $exist[$bare] = -1;
 176                  }
 177              } else {
 178                  $exist[$bare] = is_null($val->personal)
 179                      ? $key
 180                      : -1;
 181              }
 182          }
 183  
 184          foreach (array_reverse($remove) as $key) {
 185              unset($this[$key]);
 186          }
 187  
 188          $this->_filter = $old;
 189      }
 190  
 191      /**
 192       * Group count.
 193       *
 194       * @return integer  The number of groups in the list.
 195       */
 196      public function groupCount()
 197      {
 198          $ret = 0;
 199  
 200          foreach ($this->_data as $val) {
 201              if ($val instanceof Horde_Mail_Rfc822_Group) {
 202                  ++$ret;
 203              }
 204          }
 205  
 206          return $ret;
 207      }
 208  
 209      /**
 210       * Set the Iterator filter.
 211       *
 212       * @param integer $mask  Filter masks.
 213       * @param mixed $filter  An e-mail, or as list of e-mails, to filter by.
 214       */
 215      public function setIteratorFilter($mask = 0, $filter = null)
 216      {
 217          $this->_filter = array();
 218  
 219          if ($mask) {
 220              $this->_filter['mask'] = $mask;
 221          }
 222  
 223          if (!is_null($filter)) {
 224              $rfc822 = new Horde_Mail_Rfc822();
 225              $this->_filter['filter'] = $rfc822->parseAddressList($filter);
 226          }
 227      }
 228  
 229      /**
 230       */
 231      protected function _writeAddress($opts)
 232      {
 233          $out = array();
 234  
 235          foreach ($this->_data as $val) {
 236              $out[] = $val->writeAddress($opts);
 237          }
 238  
 239          return implode(', ', $out);
 240      }
 241  
 242      /**
 243       */
 244      public function match($ob)
 245      {
 246          if (!($ob instanceof Horde_Mail_Rfc822_List)) {
 247              $ob = new Horde_Mail_Rfc822_List($ob);
 248          }
 249  
 250          $a = $this->bare_addresses;
 251          sort($a);
 252          $b = $ob->bare_addresses;
 253          sort($b);
 254  
 255          return ($a == $b);
 256      }
 257  
 258      /**
 259       * Does this list contain the given e-mail address?
 260       *
 261       * @param mixed $address  An e-mail address.
 262       *
 263       * @return boolean  True if the e-mail address is contained in the list.
 264       */
 265      public function contains($address)
 266      {
 267          $ob = new Horde_Mail_Rfc822_Address($address);
 268  
 269          foreach ($this->raw_addresses as $val) {
 270              if ($val->match($ob)) {
 271                  return true;
 272              }
 273          }
 274  
 275          return false;
 276      }
 277  
 278      /**
 279       * Normalize objects to add to list.
 280       *
 281       * @param mixed $obs  Address data to store in this object.
 282       *
 283       * @return array  Entries to add.
 284       */
 285      protected function _normalize($obs)
 286      {
 287          $add = array();
 288  
 289          if (!($obs instanceof Horde_Mail_Rfc822_List) &&
 290              !is_array($obs)) {
 291              $obs = array($obs);
 292          }
 293  
 294          foreach ($obs as $val) {
 295              if (is_string($val)) {
 296                  $rfc822 = new Horde_Mail_Rfc822();
 297                  $val = $rfc822->parseAddressList($val);
 298              }
 299  
 300              if ($val instanceof Horde_Mail_Rfc822_List) {
 301                  $val->setIteratorFilter(self::BASE_ELEMENTS);
 302                  foreach ($val as $val2) {
 303                      $add[] = $val2;
 304                  }
 305              } elseif ($val instanceof Horde_Mail_Rfc822_Object) {
 306                  $add[] = $val;
 307              }
 308          }
 309  
 310          return $add;
 311      }
 312  
 313      /* ArrayAccess methods. */
 314  
 315      /**
 316       */
 317      public function offsetExists($offset)
 318      {
 319          return !is_null($this[$offset]);
 320      }
 321  
 322      /**
 323       */
 324      public function offsetGet($offset)
 325      {
 326          try {
 327              $this->seek($offset);
 328              return $this->current();
 329          } catch (OutOfBoundsException $e) {
 330              return null;
 331          }
 332      }
 333  
 334      /**
 335       */
 336      public function offsetSet($offset, $value)
 337      {
 338          if ($ob = $this[$offset]) {
 339              if (is_null($this->_ptr['subidx'])) {
 340                  $tmp = $this->_normalize($value);
 341                  if (isset($tmp[0])) {
 342                      $this->_data[$this->_ptr['idx']] = $tmp[0];
 343                  }
 344              } else {
 345                  $ob[$offset] = $value;
 346              }
 347              $this->_ptr = null;
 348          }
 349      }
 350  
 351      /**
 352       */
 353      public function offsetUnset($offset)
 354      {
 355          if ($ob = $this[$offset]) {
 356              if (is_null($this->_ptr['subidx'])) {
 357                  unset($this->_data[$this->_ptr['idx']]);
 358                  $this->_data = array_values($this->_data);
 359              } else {
 360                  unset($ob->addresses[$this->_ptr['subidx']]);
 361              }
 362              $this->_ptr = null;
 363          }
 364      }
 365  
 366      /* Countable methods. */
 367  
 368      /**
 369       * Address count.
 370       *
 371       * @return integer  The number of addresses.
 372       */
 373      public function count()
 374      {
 375          return count($this->addresses);
 376      }
 377  
 378      /* Iterator methods. */
 379  
 380      public function current()
 381      {
 382          if (!$this->valid()) {
 383              return null;
 384          }
 385  
 386          $ob = $this->_data[$this->_ptr['idx']];
 387  
 388          return is_null($this->_ptr['subidx'])
 389              ? $ob
 390              : $ob->addresses[$this->_ptr['subidx']];
 391      }
 392  
 393      public function key()
 394      {
 395          return $this->_ptr['key'];
 396      }
 397  
 398      public function next()
 399      {
 400          if (is_null($this->_ptr['subidx'])) {
 401              $curr = $this->current();
 402              if (($curr instanceof Horde_Mail_Rfc822_Group) && count($curr)) {
 403                  $this->_ptr['subidx'] = 0;
 404              } else {
 405                  ++$this->_ptr['idx'];
 406              }
 407              $curr = $this->current();
 408          } elseif (!($curr = $this->_data[$this->_ptr['idx']]->addresses[++$this->_ptr['subidx']])) {
 409              $this->_ptr['subidx'] = null;
 410              ++$this->_ptr['idx'];
 411              $curr = $this->current();
 412          }
 413  
 414          if (!is_null($curr)) {
 415              if (!empty($this->_filter) && $this->_iteratorFilter($curr)) {
 416                  $this->next();
 417              } else {
 418                  ++$this->_ptr['key'];
 419              }
 420          }
 421      }
 422  
 423      public function rewind()
 424      {
 425          $this->_ptr = array(
 426              'idx' => 0,
 427              'key' => 0,
 428              'subidx' => null
 429          );
 430  
 431          if ($this->valid() &&
 432              !empty($this->_filter) &&
 433              $this->_iteratorFilter($this->current())) {
 434              $this->next();
 435              $this->_ptr['key'] = 0;
 436          }
 437      }
 438  
 439      public function valid()
 440      {
 441          return (!empty($this->_ptr) && isset($this->_data[$this->_ptr['idx']]));
 442      }
 443  
 444      public function seek($position)
 445      {
 446          if (!$this->valid() ||
 447              ($position < $this->_ptr['key'])) {
 448              $this->rewind();
 449          }
 450  
 451          for ($i = $this->_ptr['key']; ; ++$i) {
 452              if ($i == $position) {
 453                  return;
 454              }
 455  
 456              $this->next();
 457              if (!$this->valid()) {
 458                  throw new OutOfBoundsException('Position not found.');
 459              }
 460          }
 461      }
 462  
 463      protected function _iteratorFilter($ob)
 464      {
 465          if (!empty($this->_filter['mask'])) {
 466              if (($this->_filter['mask'] & self::HIDE_GROUPS) &&
 467                  ($ob instanceof Horde_Mail_Rfc822_Group)) {
 468                  return true;
 469              }
 470  
 471              if (($this->_filter['mask'] & self::BASE_ELEMENTS) &&
 472                  !is_null($this->_ptr['subidx'])) {
 473                  return true;
 474              }
 475          }
 476  
 477          if (!empty($this->_filter['filter']) &&
 478              ($ob instanceof Horde_Mail_Rfc822_Address)) {
 479              foreach ($this->_filter['filter'] as $val) {
 480                  if ($ob->match($val)) {
 481                      return true;
 482                  }
 483              }
 484          }
 485  
 486          return false;
 487      }
 488  
 489      /* Serializable methods. */
 490  
 491      public function serialize()
 492      {
 493          return serialize($this->_data);
 494      }
 495  
 496      public function unserialize($data)
 497      {
 498          $this->_data = unserialize($data);
 499      }
 500  
 501  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1