LDAPAccountManager/lam/lib/3rdParty/composer/pear-pear.horde.org/Horde_Mail/Horde/Mail/Rfc822/List.php

519 lines
13 KiB
PHP

<?php
/**
* Copyright 2012-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsd.
*
* @category Horde
* @copyright 2012-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd New BSD License
* @package Mail
*/
/**
* Container object for a collection of RFC 822 elements.
*
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2012-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd New BSD License
* @package Mail
*
* @property-read array $addresses The list of all addresses (address
* w/personal parts).
* @property-read array $bare_addresses The list of all addresses (mail@host).
* @property-read array $bare_addresses_idn The list of all addresses
* (mail@host; IDN encoded).
* (@since 2.1.0)
* @property-read array $base_addresses The list of ONLY base addresses
* (Address objects).
* @property-read array $raw_addresses The list of all addresses (Address
* objects).
*/
class Horde_Mail_Rfc822_List
extends Horde_Mail_Rfc822_Object
implements ArrayAccess, Countable, SeekableIterator, Serializable
{
/** Filter masks. */
const HIDE_GROUPS = 1;
const BASE_ELEMENTS = 2;
/**
* List data.
*
* @var array
*/
protected $_data = array();
/**
* Current Iterator filter.
*
* @var array
*/
protected $_filter = array();
/**
* Current Iterator pointer.
*
* @var array
*/
protected $_ptr;
/**
* Constructor.
*
* @param mixed $obs Address data to store in this object.
*/
public function __construct($obs = null)
{
if (!is_null($obs)) {
$this->add($obs);
}
}
/**
*/
public function __get($name)
{
switch ($name) {
case 'addresses':
case 'bare_addresses':
case 'bare_addresses_idn':
case 'base_addresses':
case 'raw_addresses':
$old = $this->_filter;
$mask = ($name == 'base_addresses')
? self::BASE_ELEMENTS
: self::HIDE_GROUPS;
$this->setIteratorFilter($mask, empty($old['filter']) ? null : $old['filter']);
$out = array();
foreach ($this as $val) {
switch ($name) {
case 'addresses':
$out[] = strval($val);
break;
case 'bare_addresses':
$out[] = $val->bare_address;
break;
case 'bare_addresses_idn':
$out[] = $val->bare_address_idn;
break;
case 'base_addresses':
case 'raw_addresses':
$out[] = clone $val;
break;
}
}
$this->_filter = $old;
return $out;
}
}
/**
* Add objects to the container.
*
* @param mixed $obs Address data to store in this object.
*/
public function add($obs)
{
foreach ($this->_normalize($obs) as $val) {
$this->_data[] = $val;
}
}
/**
* Remove addresses from the container. This method ignores Group objects.
*
* @param mixed $obs Addresses to remove.
*/
public function remove($obs)
{
$old = $this->_filter;
$this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS);
foreach ($this->_normalize($obs) as $val) {
$remove = array();
foreach ($this as $key => $val2) {
if ($val2->match($val)) {
$remove[] = $key;
}
}
foreach (array_reverse($remove) as $key) {
unset($this[$key]);
}
}
$this->_filter = $old;
}
/**
* Removes duplicate addresses from list. This method ignores Group
* objects.
*/
public function unique()
{
$exist = $remove = array();
$old = $this->_filter;
$this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS);
// For duplicates, we use the first address that contains personal
// information.
foreach ($this as $key => $val) {
$bare = $val->bare_address;
if (isset($exist[$bare])) {
if (($exist[$bare] == -1) || is_null($val->personal)) {
$remove[] = $key;
} else {
$remove[] = $exist[$bare];
$exist[$bare] = -1;
}
} else {
$exist[$bare] = is_null($val->personal)
? $key
: -1;
}
}
foreach (array_reverse($remove) as $key) {
unset($this[$key]);
}
$this->_filter = $old;
}
/**
* Group count.
*
* @return integer The number of groups in the list.
*/
public function groupCount()
{
$ret = 0;
foreach ($this->_data as $val) {
if ($val instanceof Horde_Mail_Rfc822_Group) {
++$ret;
}
}
return $ret;
}
/**
* Set the Iterator filter.
*
* @param integer $mask Filter masks.
* @param mixed $filter An e-mail, or as list of e-mails, to filter by.
*/
public function setIteratorFilter($mask = 0, $filter = null)
{
$this->_filter = array();
if ($mask) {
$this->_filter['mask'] = $mask;
}
if (!is_null($filter)) {
$rfc822 = new Horde_Mail_Rfc822();
$this->_filter['filter'] = $rfc822->parseAddressList($filter);
}
}
/**
*/
protected function _writeAddress($opts)
{
$out = array();
foreach ($this->_data as $val) {
$out[] = $val->writeAddress($opts);
}
return implode(', ', $out);
}
/**
*/
public function match($ob)
{
if (!($ob instanceof Horde_Mail_Rfc822_List)) {
$ob = new Horde_Mail_Rfc822_List($ob);
}
$a = $this->bare_addresses;
sort($a);
$b = $ob->bare_addresses;
sort($b);
return ($a == $b);
}
/**
* Does this list contain the given e-mail address?
*
* @param mixed $address An e-mail address.
*
* @return boolean True if the e-mail address is contained in the list.
*/
public function contains($address)
{
$ob = new Horde_Mail_Rfc822_Address($address);
foreach ($this->raw_addresses as $val) {
if ($val->match($ob)) {
return true;
}
}
return false;
}
/**
* Convenience method to return the first element in a list.
*
* Useful since it allows chaining; older PHP versions did not allow array
* access dereferencing from the results of a function call.
*
* @since 2.5.0
*
* @return Horde_Mail_Rfc822_Object Rfc822 object, or null if no object.
*/
public function first()
{
return $this[0];
}
/**
* Normalize objects to add to list.
*
* @param mixed $obs Address data to store in this object.
*
* @return array Entries to add.
*/
protected function _normalize($obs)
{
$add = array();
if (!($obs instanceof Horde_Mail_Rfc822_List) &&
!is_array($obs)) {
$obs = array($obs);
}
foreach ($obs as $val) {
if (is_string($val)) {
$rfc822 = new Horde_Mail_Rfc822();
$val = $rfc822->parseAddressList($val);
}
if ($val instanceof Horde_Mail_Rfc822_List) {
$val->setIteratorFilter(self::BASE_ELEMENTS);
foreach ($val as $val2) {
$add[] = $val2;
}
} elseif ($val instanceof Horde_Mail_Rfc822_Object) {
$add[] = $val;
}
}
return $add;
}
/* ArrayAccess methods. */
/**
*/
public function offsetExists($offset)
{
return !is_null($this[$offset]);
}
/**
*/
public function offsetGet($offset)
{
try {
$this->seek($offset);
return $this->current();
} catch (OutOfBoundsException $e) {
return null;
}
}
/**
*/
public function offsetSet($offset, $value)
{
if ($ob = $this[$offset]) {
if (is_null($this->_ptr['subidx'])) {
$tmp = $this->_normalize($value);
if (isset($tmp[0])) {
$this->_data[$this->_ptr['idx']] = $tmp[0];
}
} else {
$ob[$offset] = $value;
}
$this->_ptr = null;
}
}
/**
*/
public function offsetUnset($offset)
{
if ($ob = $this[$offset]) {
if (is_null($this->_ptr['subidx'])) {
unset($this->_data[$this->_ptr['idx']]);
$this->_data = array_values($this->_data);
} else {
unset($ob->addresses[$this->_ptr['subidx']]);
}
$this->_ptr = null;
}
}
/* Countable methods. */
/**
* Address count.
*
* @return integer The number of addresses.
*/
public function count()
{
return count($this->addresses);
}
/* Iterator methods. */
public function current()
{
if (!$this->valid()) {
return null;
}
$ob = $this->_data[$this->_ptr['idx']];
return is_null($this->_ptr['subidx'])
? $ob
: $ob->addresses[$this->_ptr['subidx']];
}
public function key()
{
return $this->_ptr['key'];
}
public function next()
{
if (is_null($this->_ptr['subidx'])) {
$curr = $this->current();
if (($curr instanceof Horde_Mail_Rfc822_Group) && count($curr)) {
$this->_ptr['subidx'] = 0;
} else {
++$this->_ptr['idx'];
}
$curr = $this->current();
} elseif (!($curr = $this->_data[$this->_ptr['idx']]->addresses[++$this->_ptr['subidx']])) {
$this->_ptr['subidx'] = null;
++$this->_ptr['idx'];
$curr = $this->current();
}
if (!is_null($curr)) {
if (!empty($this->_filter) && $this->_iteratorFilter($curr)) {
$this->next();
} else {
++$this->_ptr['key'];
}
}
}
public function rewind()
{
$this->_ptr = array(
'idx' => 0,
'key' => 0,
'subidx' => null
);
if ($this->valid() &&
!empty($this->_filter) &&
$this->_iteratorFilter($this->current())) {
$this->next();
$this->_ptr['key'] = 0;
}
}
public function valid()
{
return (!empty($this->_ptr) && isset($this->_data[$this->_ptr['idx']]));
}
public function seek($position)
{
if (!$this->valid() ||
($position < $this->_ptr['key'])) {
$this->rewind();
}
for ($i = $this->_ptr['key']; ; ++$i) {
if ($i == $position) {
return;
}
$this->next();
if (!$this->valid()) {
throw new OutOfBoundsException('Position not found.');
}
}
}
protected function _iteratorFilter($ob)
{
if (!empty($this->_filter['mask'])) {
if (($this->_filter['mask'] & self::HIDE_GROUPS) &&
($ob instanceof Horde_Mail_Rfc822_Group)) {
return true;
}
if (($this->_filter['mask'] & self::BASE_ELEMENTS) &&
!is_null($this->_ptr['subidx'])) {
return true;
}
}
if (!empty($this->_filter['filter']) &&
($ob instanceof Horde_Mail_Rfc822_Address)) {
foreach ($this->_filter['filter'] as $val) {
if ($ob->match($val)) {
return true;
}
}
}
return false;
}
/* Serializable methods. */
public function serialize()
{
return serialize($this->_data);
}
public function unserialize($data)
{
$this->_data = unserialize($data);
}
}