* @category Horde * @copyright 2014-2017 Horde LLC * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 * @package Mime * @since 2.5.0 */ class Horde_Mime_Id { /* Constants for idArithmetic() method. */ const ID_DOWN = 1; const ID_NEXT = 2; const ID_PREV = 3; const ID_UP = 4; /** * MIME ID. * * @var string */ public $id; /** * Constructor. * * @param string $id MIME ID. */ public function __construct($id) { $this->id = $id; } /** */ public function __toString() { return $this->id; } /** * Performs MIME ID "arithmetic". * * @param string $action One of: * - ID_DOWN: ID of child. Note: ID_DOWN will first traverse to "$id.0" * if given an ID *NOT* of the form "$id.0". If given an ID of * the form "$id.0", ID_DOWN will traverse to "$id.1". This * behavior can be avoided if 'no_rfc822' option is set. * - ID_NEXT: ID of next sibling. * - ID_PREV: ID of previous sibling. * - ID_UP: ID of parent. Note: ID_UP will first traverse to "$id.0" if * given an ID *NOT* of the form "$id.0". If given an ID of the * form "$id.0", ID_UP will traverse to "$id". This behavior can * be avoided if 'no_rfc822' option is set. * @param array $options Additional options: * - count: (integer) How many levels to traverse. * DEFAULT: 1 * - no_rfc822: (boolean) Don't traverse RFC 822 sub-levels. * DEFAULT: false * * @return mixed The resulting ID string, or null if that ID can not * exist. */ public function idArithmetic($action, array $options = array()) { return $this->_idArithmetic($this->id, $action, array_merge(array( 'count' => 1 ), $options)); } /** * @see idArithmetic() */ protected function _idArithmetic($id, $action, $options) { $pos = strrpos($id, '.'); $end = ($pos === false) ? $id : substr($id, $pos + 1); switch ($action) { case self::ID_DOWN: if ($end == '0') { $id = ($pos === false) ? 1 : substr_replace($id, '1', $pos + 1); } else { $id .= empty($options['no_rfc822']) ? '.0' : '.1'; } break; case self::ID_NEXT: ++$end; $id = ($pos === false) ? $end : substr_replace($id, $end, $pos + 1); break; case self::ID_PREV: if (($end == '0') || (empty($options['no_rfc822']) && ($end == '1'))) { $id = null; } elseif ($pos === false) { $id = --$end; } else { $id = substr_replace($id, --$end, $pos + 1); } break; case self::ID_UP: if ($pos === false) { $id = ($end == '0') ? null : '0'; } elseif (!empty($options['no_rfc822']) || ($end == '0')) { $id = substr($id, 0, $pos); } else { $id = substr_replace($id, '0', $pos + 1); } break; } return (!is_null($id) && --$options['count']) ? $this->_idArithmetic($id, $action, $options) : $id; } /** * Determines if a given MIME ID lives underneath a base ID. * * @param string $id The MIME ID to query. * * @return boolean Whether $id lives under the base ID ($this->id). */ public function isChild($id) { $base = (substr($this->id, -2) == '.0') ? substr($this->id, 0, -1) : rtrim($this->id, '.') . '.'; return ((($base == 0) && ($id != 0)) || (strpos(strval($id), strval($base)) === 0)); } }