* @category Horde * @copyright 2009-2017 Horde LLC * @license http://www.horde.org/licenses/gpl GPL * @package IMP */ class IMP_Flags implements ArrayAccess, Serializable { /** * Has the object data changed? * * @var boolean */ public $changed = false; /** * Does the msglist_flags hook exist? * * @var boolean */ protected $_flaghook = true; /** * The list of internal flags. * * @var array */ protected $_flags = array(); /** * The list of user flags. * * @var array */ protected $_userflags = array(); /** * Constructor. */ public function __construct() { /* Build list of default flags. */ foreach (array('Imap', 'System') as $type) { $di = new DirectoryIterator(IMP_BASE . '/lib/Flag/' . $type); foreach ($di as $val) { if ($val->isFile()) { $cname = 'IMP_Flag_' . $type . '_' . $val->getBasename('.php'); if (class_exists($cname)) { $ob = new $cname(); $this->_flags[$ob->id] = $ob; } } } } if ($f_list = $GLOBALS['prefs']->getValue('msgflags')) { $f_list = @unserialize($f_list); if (is_array($f_list)) { foreach ($f_list as $val) { $this->_userflags[$val->id] = $val; } } } $this->changed = true; } /** * Save the flag list to the prefs backend. */ protected function _save() { global $prefs; if (!$prefs->isLocked('msgflags')) { $prefs->setValue('msgflags', serialize($this->_userflags)); } $this->changed = true; } /** * Return the raw list of flags. * * @param array $opts Additional options: * - imap: (boolean) If true, only return IMAP flags that can be set by * the user. * DEFAULT: false * - mailbox: (string) A real (not virtual) IMAP mailbox. If set, will * determine what flags are available in the mailbox. * DEFAULT: '' (no mailbox check) * * @return array An array of IMP_Flag_Base elements. */ public function getList(array $opts = array()) { if (!$GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->access(IMP_Imap::ACCESS_FLAGS)) { return array(); } $ret = array_merge($this->_flags, $this->_userflags); if (!empty($opts['imap'])) { foreach ($ret as $key => $val) { if (!($val instanceof IMP_Flag_Imap)) { unset($ret[$key]); } } } if (!isset($opts['mailbox']) || !strlen($opts['mailbox']) || IMP_Mailbox::get($opts['mailbox'])->search) { return array_values($ret); } /* Alter the list of flags for a mailbox depending on the mailbox's * PERMANENTFLAGS status. */ $permflags = IMP_Mailbox::get($opts['mailbox'])->permflags; /* Limited flags allowed in mailbox. */ foreach ($ret as $key => $val) { if (($val instanceof IMP_Flag_Imap) && !$permflags->allowed($val->imapflag)) { unset($ret[$key]); } } /* Get list of unknown flags. */ if ($GLOBALS['prefs']->getValue('show_all_flags')) { /* Get list of IMAP flags. */ $imapflags = array(); foreach ($ret as $val) { if ($val instanceof IMP_Flag_Imap) { $imapflags[] = $val->imapflag; } } foreach ($permflags as $val) { if (!in_array($val, $imapflags)) { $ret[] = new IMP_Flag_User($val); } } } return array_values($ret); } /** * Add a user-defined IMAP flag. * * @param string $label The label to use for the new flag. * * @return string The IMAP flag name. * @throws IMP_Exception */ public function addFlag($label) { if (strlen($label) === 0) { throw new IMP_Exception(_("Flag name must not be empty.")); } $ob = new IMP_Flag_User($label); if (isset($this->_userflags[$ob->id])) { throw new IMP_Exception(_("Flag name already exists.")); } $this->_userflags[$ob->id] = $ob; $this->_save(); return $ob->imapflag; } /** * Updates flag properties. * * @param string $key The flag key. * @param string $type The property to update. Either 'bgcolor' or * 'label'. * @param string $data The updated data. */ public function updateFlag($key, $type, $data) { if (isset($this->_userflags[$key])) { $ob = clone $this->_userflags[$key]; } elseif (isset($this->_flags[$key])) { $ob = clone $this->_flags[$key]; } else { return; } $ob->$type = $data; if (isset($this->_flags[$key]) && ($this->_flags[$key] == $ob)) { unset($this->_userflags[$key]); } else { $this->_userflags[$key] = $ob; } $this->_save(); } /** * Parse a list of flag information. * * @param array $opts Options: *
* - flags: (array) IMAP flag info. A lowercase list of flags returned
* by the IMAP server.
* - headers: (Horde_Mime_Headers) Determines message information
* from a headers object.
* - runhook: (array) Run the msglist_flags hook? If yes, input is
* return from IMP_Mailbox_List#getMailboxArray().
* - personal: (mixed) Personal message info. Either a list of To
* addresses (Horde_Mail_Rfc822_List object) or the identity
* that matched the address list.
*
*
* @return array A list of IMP_Flag_Base objects.
*/
public function parse(array $opts = array())
{
global $injector;
$opts = array_merge(array(
'flags' => array(),
'headers' => null,
'personal' => null
), $opts);
if (!empty($opts['runhook']) && $this->_flaghook) {
try {
$opts['flags'] = array_merge(
$opts['flags'],
$injector->getInstance('Horde_Core_Hooks')->callHook(
'msglist_flags',
'imp',
array($opts['runhook'])
)
);
} catch (Horde_Exception_HookNotSet $e) {
$this->_flaghook = false;
}
}
$ret = array();
foreach (array_merge($this->_flags, $this->_userflags) as $val) {
if ($val instanceof IMP_Flag_System_Match_Address) {
if (!is_null($opts['personal']) &&
$val->match($opts['personal'])) {
$ret[] = $val;
}
} elseif (($val instanceof IMP_Flag_Imap) ||
($val instanceof IMP_Flag_System_Match_Flag)) {
if ($val->match($opts['flags'])) {
$ret[] = $val;
}
} elseif ($val instanceof IMP_Flag_System_Match_Header) {
if (!is_null($opts['headers']) &&
$val->match($opts['headers'])) {
$ret[] = $val;
}
}
}
return $ret;
}
/**
* Process a flag ID formatted for use in form data.
*
* @param string $id The ID from form data.
*
* @return array Two element array:
* - flag: (string) The flag name.
* - set: (boolean) Whether the flag should be set or not.
*/
public function parseFormId($id)
{
return (strpos($id, '0\\') === 0)
? array('flag' => substr($id, 2), 'set' => false)
: array('flag' => $id, 'set' => true);
}
/**
* Returns a list of flags that have changed due to IMAP flag changes.
*
* @param array $flags The list of IMAP flags added/removed.
* @param boolean $add True if these flags were added, false if they were
* removed.
*
* @return array Array with two keys: 'add' and 'remove'. Each key
* contains a list of IMP_Flag_Base objects.
*/
public function changed($flags, $add)
{
$ret = array(
'add' => array(),
'remove' => array()
);
$obs = array();
foreach ($flags as $val) {
if ($tmp = $this[$val]) {
$obs[] = $tmp;
}
}
if ($add) {
$ret['add'] = $obs;
} else {
$ret['remove'] = $obs;
}
foreach (array_merge($this->_flags, $this->_userflags) as $val) {
$res = $val->changed($obs, $add);
if ($res === false) {
$ret['remove'][] = $val;
} elseif ($res === true) {
$ret['add'][] = $val;
}
}
return $ret;
}
/* ArrayAccess methods. */
/**
*/
public function offsetExists($offset)
{
return isset($this->_flags[$offset]) ||
isset($this->_userflags[$offset]);
}
/**
*/
public function offsetGet($offset)
{
if (isset($this->_flags[$offset])) {
return $this->_flags[$offset];
} elseif (isset($this->_userflags[$offset])) {
return $this->_userflags[$offset];
}
return null;
}
/**
* @throws InvalidArgumentException
*/
public function offsetSet($offset, $value)
{
throw new InvalidArgumentException('Use addFlag()/updateFlag()');
}
/**
*/
public function offsetUnset($offset)
{
if (isset($this->_userflags[$offset])) {
unset($this->_userflags[$offset]);
$this->_save();
}
}
/* Serializable methods. */
/**
*/
public function serialize()
{
return $GLOBALS['injector']->getInstance('Horde_Pack')->pack(
array(
$this->_flags,
$this->_userflags
), array(
'compression' => false,
'phpob' => true
)
);
}
/**
*/
public function unserialize($data)
{
list(
$this->_flags,
$this->_userflags
) = $GLOBALS['injector']->getInstance('Horde_Pack')->unpack($data);
}
}