1<?php 2/** 3 * Copyright 2001-2017 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 2001-2017 Horde LLC 10 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 11 * @package Prefs 12 */ 13 14/** 15 * This class provides an interface to all identities a user might have. 16 * 17 * @author Jan Schneider <jan@horde.org> 18 * @category Horde 19 * @copyright 2001-2017 Horde LLC 20 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 21 * @package Prefs 22 */ 23class Horde_Prefs_Identity 24implements ArrayAccess, Countable, IteratorAggregate 25{ 26 /** 27 * Array containing all the user's identities. 28 * 29 * @var array 30 */ 31 protected $_identities = array(); 32 33 /** 34 * A pointer to the user's standard identity. 35 * This one is used by the methods returning values if no other one is 36 * specified. 37 * 38 * @var integer 39 */ 40 protected $_default = 0; 41 42 /** 43 * The user whose identities these are. 44 * 45 * @var string 46 */ 47 protected $_user = null; 48 49 /** 50 * Preference names. 51 * 52 * @var array 53 */ 54 protected $_prefnames = array( 55 'default_identity' => 'default_identity', 56 'from_addr' => 'from_addr', 57 'fullname' => 'fullname', 58 'id' => 'id', 59 'identities' => 'identities', 60 'properties' => array('id', 'fullname', 'from_addr') 61 ); 62 63 /** 64 * The prefs object that this Identity points to. 65 * 66 * @var Horde_Prefs 67 */ 68 protected $_prefs; 69 70 /** 71 * Constructor. 72 * 73 * @param array $params Parameters: 74 * - default_identity: (string) The preference name for the default 75 * identity. 76 * DEFAULT: 'default_identity' 77 * - from_addr: (string) The preference name for the user's from e-mail 78 * address. 79 * DEFAULT: 'from_addr' 80 * - fullname: (string) The preference name for the user's full name. 81 * DEFAULT: 'fullname' 82 * - id: (string) The preference name for the identity name. 83 * DEFAULT: 'id' 84 * - identities: (string) The preference name for the identity store. 85 * DEFAULT: 'identities' 86 * - prefs: (Horde_Prefs) [REQUIRED] The prefs object to use. 87 * - properties: (array) The list of properties for the identity. 88 * DEFAULT: array('from_addr', 'fullname', 'id') 89 * - user: (string) [REQUIRED] The user whose prefs we are handling. 90 */ 91 public function __construct($params = array()) 92 { 93 foreach (array_keys($this->_prefnames) as $val) { 94 if (isset($params[$val])) { 95 $this->_prefnames[$val] = $params[$val]; 96 } 97 } 98 $this->_prefs = $params['prefs']; 99 $this->_user = $params['user']; 100 101 if (!($this->_identities = @unserialize($this->_prefs->getValue($this->_prefnames['identities'])))) { 102 $this->_identities = $this->_prefs->getDefault($this->_prefnames['identities']); 103 } 104 105 $this->setDefault($this->_prefs->getValue($this->_prefnames['default_identity'])); 106 } 107 108 /** 109 * Creates a default identity if none exists yet and sets the preferences 110 * up if the identities are locked. 111 */ 112 public function init() 113 { 114 if (!is_array($this->_identities) || (count($this->_identities) <= 0)) { 115 foreach (array_keys($this->_prefnames) as $key) { 116 $identity[$key] = $this->_prefs->getValue($key); 117 } 118 if (empty($identity['id'])) { 119 $identity['id'] = Horde_Prefs_Translation::t("Default Identity"); 120 } 121 122 $this->_identities = array($identity); 123 $this->verify(0); 124 } 125 } 126 127 /** 128 * Saves all identities in the prefs backend. 129 */ 130 public function save() 131 { 132 $this->_prefs->setValue($this->_prefnames['identities'], serialize($this->_identities)); 133 $this->_prefs->setValue($this->_prefnames['default_identity'], $this->_default); 134 } 135 136 /** 137 * Adds a new identity to the array of identities. 138 * 139 * @param array $identity An identity hash to add. 140 * 141 * @return integer The pointer to the created identity 142 */ 143 public function add($identity = array()) 144 { 145 $this->_identities[] = $identity; 146 return count($this->_identities) - 1; 147 } 148 149 /** 150 * Returns a complete identity hash. 151 * 152 * @param integer $identity The identity to retrieve. 153 * 154 * @return array An identity hash. Returns null if the identity does not 155 * exist. 156 */ 157 public function get($identity = null) 158 { 159 if (is_null($identity)) { 160 $identity = $this->_default; 161 } 162 163 return isset($this->_identities[$identity]) 164 ? $this->_identities[$identity] 165 : null; 166 } 167 168 /** 169 * Removes an identity from the array of identities. 170 * 171 * @param integer $identity The pointer to the identity to be removed 172 * 173 * @return array The removed identity. 174 */ 175 public function delete($identity) 176 { 177 $deleted = array_splice($this->_identities, $identity, 1); 178 179 if (!empty($deleted)) { 180 foreach (array_keys($this->_identities) as $id) { 181 if ($this->setDefault($id)) { 182 break; 183 } 184 } 185 $this->save(); 186 } 187 188 return reset($deleted); 189 } 190 191 /** 192 * Returns a pointer to the current default identity. 193 * 194 * @return integer The pointer to the current default identity. 195 */ 196 public function getDefault() 197 { 198 return $this->_default; 199 } 200 201 /** 202 * Sets the current default identity. 203 * If the identity doesn't exist, the old default identity stays the same. 204 * 205 * @param integer $identity The pointer to the new default identity. 206 * 207 * @return boolean True on success, false on failure. 208 */ 209 public function setDefault($identity) 210 { 211 if (isset($this->_identities[$identity])) { 212 $this->_default = $identity; 213 return true; 214 } 215 216 return false; 217 } 218 219 /** 220 * Returns a property from one of the identities. If this value doesn't 221 * exist or is locked, the property is retrieved from the prefs backend. 222 * 223 * @param string $key The property to retrieve. 224 * @param integer $identity The identity to retrieve the property from. 225 * 226 * @return mixed The value of the property. 227 */ 228 public function getValue($key, $identity = null) 229 { 230 if (is_null($identity) || !isset($this->_identities[$identity])) { 231 $identity = $this->_default; 232 } 233 234 return (!isset($this->_identities[$identity][$key]) || $this->_prefs->isLocked($key)) 235 ? $this->_prefs->getValue($key) 236 : $this->_identities[$identity][$key]; 237 } 238 239 /** 240 * Returns an array with the specified property from all existing 241 * identities. 242 * 243 * @param string $key The property to retrieve. 244 * 245 * @return array The array with the values from all identities. 246 */ 247 public function getAll($key) 248 { 249 $list = array(); 250 251 foreach (array_keys($this->_identities) as $identity) { 252 $list[$identity] = $this->getValue($key, $identity); 253 } 254 255 return $list; 256 } 257 258 /** 259 * Sets a property with a specified value. 260 * 261 * @param string $key The property to set. 262 * @param mixed $val The value to which the property should be 263 * set. 264 * @param integer $identity The identity to set the property in. 265 * 266 * @return boolean True on success, false on failure (property was 267 * locked). 268 */ 269 public function setValue($key, $val, $identity = null) 270 { 271 if (is_null($identity)) { 272 $identity = $this->_default; 273 } 274 275 if (!$this->_prefs->isLocked($key)) { 276 $this->_identities[$identity][$key] = $val; 277 return true; 278 } 279 280 return false; 281 } 282 283 /** 284 * Returns true if all properties are locked and therefore nothing in the 285 * identities can be changed. 286 * 287 * @return boolean True if all properties are locked, false otherwise. 288 */ 289 public function isLocked() 290 { 291 foreach ($this->_prefnames['properties'] as $key) { 292 if (!$this->_prefs->isLocked($key)) { 293 return false; 294 } 295 } 296 297 return true; 298 } 299 300 /** 301 * Returns true if the given address belongs to one of the identities. 302 * 303 * @param string $key The identity key to search. 304 * @param string $value The value to search for in $key. 305 * 306 * @return boolean True if the $value was found in $key. 307 */ 308 public function hasValue($key, $value) 309 { 310 $list = $this->getAll($key); 311 312 foreach ($list as $valueB) { 313 if (!empty($valueB) && 314 strpos(Horde_String::lower($value), Horde_String::lower($valueB)) !== false) { 315 return true; 316 } 317 } 318 319 return false; 320 } 321 322 /** 323 * Verifies and sanitizes all identity properties. 324 * 325 * @param integer $identity The identity to verify. 326 * 327 * @throws Horde_Prefs_Exception 328 */ 329 public function verify($identity = null) 330 { 331 if (is_null($identity)) { 332 $identity = $this->_default; 333 } 334 335 if (!$this->getValue('id', $identity)) { 336 $this->setValue('id', Horde_Prefs_Translation::t("Unnamed"), $identity); 337 } 338 339 // To verify e-mail, first parse input, than re-parse in verify mode. 340 $ob = new Horde_Mail_Rfc822_Address($this->getValue($this->_prefnames['from_addr'], $identity)); 341 try { 342 $rfc822 = new Horde_Mail_Rfc822(); 343 $rfc822->parseAddressList($ob, array( 344 'validate' => true 345 )); 346 } catch (Horde_Mail_Exception $e) { 347 throw new Horde_Prefs_Exception(sprintf(Horde_Prefs_Translation::t("\"%s\" is not a valid email address."), strval($ob))); 348 } 349 350 $this->setValue('from_addr', strval($ob), $identity); 351 } 352 353 /** 354 * Returns the user's full name. 355 * 356 * @param integer $ident The identity to retrieve the name from. 357 * 358 * @return string The user's full name, or the user name if it doesn't 359 * exist. 360 */ 361 public function getName($ident = null) 362 { 363 if (isset($this->_names[$ident])) { 364 return $this->_names[$ident]; 365 } 366 367 $this->_names[$ident] = $this->getValue($this->_prefnames['fullname'], $ident); 368 if (!strlen($this->_names[$ident])) { 369 $this->_names[$ident] = $this->_user; 370 } 371 372 return $this->_names[$ident]; 373 } 374 375 /** 376 * Returns the from address based on the chosen identity. 377 * 378 * If no address can be found it is built from the current user. 379 * 380 * @since Horde_Prefs 2.3.0 381 * 382 * @param integer $ident The identity to retrieve the address from. 383 * 384 * @return Horde_Mail_Rfc822_Address A valid from address. 385 */ 386 public function getFromAddress($ident = null) 387 { 388 $val = $this->getValue($this->_prefnames['from_addr'], $ident); 389 if (!strlen($val)) { 390 $val = $this->_user; 391 } 392 return new Horde_Mail_Rfc822_Address($val); 393 } 394 395 /** 396 * Generates the from address to use for the default identity. 397 * 398 * @param boolean $fullname Include the fullname information. 399 * 400 * @return Horde_Mail_Rfc822_Address The default from address (object 401 * returned since 2.2.0). 402 */ 403 public function getDefaultFromAddress($fullname = false) 404 { 405 $ob = new Horde_Mail_Rfc822_Address($this->getFromAddress()); 406 $ob->personal = $fullname 407 ? $this->getValue($this->_prefnames['fullname']) 408 : null; 409 410 return $ob; 411 } 412 413 /* ArrayAccess methods. */ 414 415 /** 416 * @since 2.7.0 417 */ 418 public function offsetExists($offset) 419 { 420 return isset($this->_identities[$offset]); 421 } 422 423 /** 424 * @since 2.7.0 425 */ 426 public function offsetGet($offset) 427 { 428 return $this->get($offset); 429 } 430 431 /** 432 * @since 2.7.0 433 */ 434 public function offsetSet($offset, $value) 435 { 436 // $value is ignored. 437 $this->set($offset); 438 } 439 440 /** 441 * @since 2.7.0 442 */ 443 public function offsetUnset($offset) 444 { 445 $this->delete($offset); 446 } 447 448 /* Countable method. */ 449 450 /** 451 * @since 2.7.0 452 */ 453 public function count() 454 { 455 return count($this->_identities); 456 } 457 458 /* IteratorAggregate method. */ 459 460 /** 461 * @since 2.7.0 462 */ 463 public function getIterator() 464 { 465 return new ArrayIterator($this->_identities); 466 } 467 468} 469