Differences Between: [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]
1 <?php 2 /** 3 * Copyright 2012-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file LICENSE 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 2012-2017 Horde LLC 10 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 11 * @package Imap_Client 12 */ 13 14 /** 15 * An object implementing lookups between UIDs and message sequence numbers. 16 * 17 * @author Michael Slusarz <slusarz@horde.org> 18 * @category Horde 19 * @copyright 2012-2017 Horde LLC 20 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 21 * @package Imap_Client 22 * @since 2.1.0 23 * 24 * @property-read array $map The raw ID mapping data. 25 * @property-read Horde_Imap_Client_Ids $seq The sorted sequence values. 26 * @property-read Horde_Imap_Client_Ids $uids The sorted UIDs. 27 */ 28 class Horde_Imap_Client_Ids_Map implements Countable, IteratorAggregate, Serializable 29 { 30 /** 31 * Sequence -> UID mapping. 32 * 33 * @var array 34 */ 35 protected $_ids = array(); 36 37 /** 38 * Is the array sorted? 39 * 40 * @var boolean 41 */ 42 protected $_sorted = true; 43 44 /** 45 * Constructor. 46 * 47 * @param array $ids Array of sequence -> UID mapping. 48 */ 49 public function __construct(array $ids = array()) 50 { 51 $this->update($ids); 52 } 53 54 /** 55 */ 56 public function __get($name) 57 { 58 switch ($name) { 59 case 'map': 60 return $this->_ids; 61 62 case 'seq': 63 $this->sort(); 64 return new Horde_Imap_Client_Ids(array_keys($this->_ids), true); 65 66 case 'uids': 67 $this->sort(); 68 return new Horde_Imap_Client_Ids($this->_ids); 69 } 70 } 71 72 /** 73 * Updates the mapping. 74 * 75 * @param array $ids Array of sequence -> UID mapping. 76 * 77 * @return boolean True if the mapping changed. 78 */ 79 public function update($ids) 80 { 81 if (empty($ids)) { 82 return false; 83 } elseif (empty($this->_ids)) { 84 $this->_ids = $ids; 85 $change = true; 86 } else { 87 $change = false; 88 foreach ($ids as $k => $v) { 89 if (!isset($this->_ids[$k]) || ($this->_ids[$k] != $v)) { 90 $this->_ids[$k] = $v; 91 $change = true; 92 } 93 } 94 } 95 96 if ($change) { 97 $this->_sorted = false; 98 } 99 100 return $change; 101 } 102 103 /** 104 * Create a Sequence <-> UID lookup table. 105 * 106 * @param Horde_Imap_Client_Ids $ids IDs to lookup. 107 * 108 * @return array Keys are sequence numbers, values are UIDs. 109 */ 110 public function lookup(Horde_Imap_Client_Ids $ids) 111 { 112 if ($ids->all) { 113 return $this->_ids; 114 } elseif ($ids->sequence) { 115 return array_intersect_key($this->_ids, array_flip($ids->ids)); 116 } 117 118 return array_intersect($this->_ids, $ids->ids); 119 } 120 121 /** 122 * Removes messages from the ID mapping. 123 * 124 * @param Horde_Imap_Client_Ids $ids IDs to remove. 125 */ 126 public function remove(Horde_Imap_Client_Ids $ids) 127 { 128 /* For sequence numbers, we need to reindex anytime we have an index 129 * that appears equal to or after a previously seen index. If an IMAP 130 * server is smart, it will expunge in reverse order instead. */ 131 if ($ids->sequence) { 132 $remove = $ids->ids; 133 } else { 134 $ids->sort(); 135 $remove = array_reverse(array_keys($this->lookup($ids))); 136 } 137 138 if (empty($remove)) { 139 return; 140 } 141 142 $this->sort(); 143 144 if (count($remove) == count($this->_ids) && 145 !array_diff($remove, array_keys($this->_ids))) { 146 $this->_ids = array(); 147 return; 148 } 149 150 /* Find the minimum sequence number to remove. We know entries before 151 * this are untouched so no need to process them multiple times. */ 152 $first = min($remove); 153 $edit = $newids = array(); 154 foreach (array_keys($this->_ids) as $i => $seq) { 155 if ($seq >= $first) { 156 $i += (($seq == $first) ? 0 : 1); 157 $newids = array_slice($this->_ids, 0, $i, true); 158 $edit = array_slice($this->_ids, $i + (($seq == $first) ? 0 : 1), null, true); 159 break; 160 } 161 } 162 163 if (!empty($edit)) { 164 foreach ($remove as $val) { 165 $found = false; 166 $tmp = array(); 167 168 foreach (array_keys($edit) as $i => $seq) { 169 if ($found) { 170 $tmp[$seq - 1] = $edit[$seq]; 171 } elseif ($seq >= $val) { 172 $tmp = array_slice($edit, 0, ($seq == $val) ? $i : $i + 1, true); 173 $found = true; 174 } 175 } 176 177 $edit = $tmp; 178 } 179 } 180 181 $this->_ids = $newids + $edit; 182 } 183 184 /** 185 * Sort the map. 186 */ 187 public function sort() 188 { 189 if (!$this->_sorted) { 190 ksort($this->_ids, SORT_NUMERIC); 191 $this->_sorted = true; 192 } 193 } 194 195 /* Countable methods. */ 196 197 /** 198 */ 199 public function count() 200 { 201 return count($this->_ids); 202 } 203 204 /* IteratorAggregate method. */ 205 206 /** 207 */ 208 public function getIterator() 209 { 210 return new ArrayIterator($this->_ids); 211 } 212 213 /* Serializable methods. */ 214 215 /** 216 */ 217 public function serialize() 218 { 219 /* Sort before storing; provides more compressible representation. */ 220 $this->sort(); 221 222 return json_encode(array( 223 strval(new Horde_Imap_Client_Ids(array_keys($this->_ids))), 224 strval(new Horde_Imap_Client_Ids(array_values($this->_ids))) 225 )); 226 } 227 228 /** 229 */ 230 public function unserialize($data) 231 { 232 $data = json_decode($data, true); 233 234 $keys = new Horde_Imap_Client_Ids($data[0]); 235 $vals = new Horde_Imap_Client_Ids($data[1]); 236 $this->_ids = array_combine($keys->ids, $vals->ids); 237 238 /* Guaranteed to be sorted if unserializing. */ 239 $this->_sorted = true; 240 } 241 242 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body