[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Copyright 2012-2014 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 2012-2014 Horde LLC 10 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 11 * @package Imap_Client 12 */ 13 14 /** 15 * Client sorting methods for the Socket driver. 16 * 17 * NOTE: This class is NOT intended to be accessed outside of a Base object. 18 * There is NO guarantees that the API of this class will not change across 19 * versions. 20 * 21 * @author Michael Slusarz <[email protected]> 22 * @category Horde 23 * @copyright 2012-2014 Horde LLC 24 * @internal 25 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 26 * @package Imap_Client 27 */ 28 class Horde_Imap_Client_Socket_ClientSort 29 { 30 /** 31 * Socket object. 32 * 33 * @var Horde_Imap_Client_Socket 34 */ 35 protected $_socket; 36 37 /** 38 * Constructor. 39 * 40 * @param Horde_Imap_Client_Socket $socket Socket object. 41 */ 42 public function __construct(Horde_Imap_Client_Socket $socket) 43 { 44 $this->_socket = $socket; 45 } 46 47 /** 48 * Sort search results client side if the server does not support the SORT 49 * IMAP extension (RFC 5256). 50 * 51 * @param Horde_Imap_Client_Ids $res The search results. 52 * @param array $opts The options to _search(). 53 * 54 * @return array The sort results. 55 * 56 * @throws Horde_Imap_Client_Exception 57 */ 58 public function clientSort($res, $opts) 59 { 60 if (!count($res)) { 61 return $res; 62 } 63 64 /* Generate the FETCH command needed. */ 65 $query = new Horde_Imap_Client_Fetch_Query(); 66 67 foreach ($opts['sort'] as $val) { 68 switch ($val) { 69 case Horde_Imap_Client::SORT_ARRIVAL: 70 $query->imapDate(); 71 break; 72 73 case Horde_Imap_Client::SORT_DATE: 74 $query->imapDate(); 75 $query->envelope(); 76 break; 77 78 case Horde_Imap_Client::SORT_CC: 79 case Horde_Imap_Client::SORT_DISPLAYFROM: 80 case Horde_Imap_Client::SORT_DISPLAYTO: 81 case Horde_Imap_Client::SORT_FROM: 82 case Horde_Imap_Client::SORT_SUBJECT: 83 case Horde_Imap_Client::SORT_TO: 84 $query->envelope(); 85 break; 86 87 case Horde_Imap_Client::SORT_SIZE: 88 $query->size(); 89 break; 90 } 91 } 92 93 if (!count($query)) { 94 return $res; 95 } 96 97 $mbox = $this->_socket->currentMailbox(); 98 $fetch_res = $this->_socket->fetch($mbox['mailbox'], $query, array( 99 'ids' => $res 100 )); 101 102 return $this->_clientSortProcess($res->ids, $fetch_res, $opts['sort']); 103 } 104 105 /** 106 * If server does not support the THREAD IMAP extension (RFC 5256), do 107 * ORDEREDSUBJECT threading on the client side. 108 * 109 * @param Horde_Imap_Client_Fetch_Results $data Fetch results. 110 * @param boolean $uids Are IDs UIDs? 111 * 112 * @return array The thread sort results. 113 */ 114 public function threadOrderedSubject(Horde_Imap_Client_Fetch_Results $data, 115 $uids) 116 { 117 $dates = $this->_getSentDates($data, $data->ids()); 118 $out = $sorted = $tsort = array(); 119 120 foreach ($data as $k => $v) { 121 $subject = strval(new Horde_Imap_Client_Data_BaseSubject($v->getEnvelope()->subject)); 122 $sorted[$subject][$k] = $dates[$k]; 123 } 124 125 /* Step 1: Sort by base subject (already done). 126 * Step 2: Sort by sent date within each thread. */ 127 foreach (array_keys($sorted) as $key) { 128 asort($sorted[$key], SORT_NUMERIC); 129 $tsort[$key] = reset($sorted[$key]); 130 } 131 132 /* Step 3: Sort by the sent date of the first message in the 133 * thread. */ 134 asort($tsort, SORT_NUMERIC); 135 136 /* Now, $tsort contains the order of the threads, and each thread 137 * is sorted in $sorted. */ 138 foreach (array_keys($tsort) as $key) { 139 $keys = array_keys($sorted[$key]); 140 $out[$keys[0]] = array( 141 $keys[0] => 0 142 ) + array_fill_keys(array_slice($keys, 1) , 1); 143 } 144 145 return new Horde_Imap_Client_Data_Thread($out, $uids ? 'uid' : 'sequence'); 146 } 147 148 /** 149 */ 150 protected function _clientSortProcess($res, $fetch_res, $sort) 151 { 152 /* The initial sort is on the entire set. */ 153 $slices = array(0 => $res); 154 $reverse = false; 155 156 foreach ($sort as $val) { 157 if ($val == Horde_Imap_Client::SORT_REVERSE) { 158 $reverse = true; 159 continue; 160 } 161 162 $slices_list = $slices; 163 $slices = array(); 164 165 foreach ($slices_list as $slice_start => $slice) { 166 $sorted = array(); 167 168 if ($reverse) { 169 $slice = array_reverse($slice); 170 } 171 172 switch ($val) { 173 case Horde_Imap_Client::SORT_SEQUENCE: 174 /* There is no requirement that IDs be returned in 175 * sequence order (see RFC 4549 [4.3.1]). So we must sort 176 * ourselves. */ 177 $sorted = array_flip($slice); 178 ksort($sorted, SORT_NUMERIC); 179 break; 180 181 case Horde_Imap_Client::SORT_SIZE: 182 foreach ($slice as $num) { 183 $sorted[$num] = $fetch_res[$num]->getSize(); 184 } 185 asort($sorted, SORT_NUMERIC); 186 break; 187 188 case Horde_Imap_Client::SORT_DISPLAYFROM: 189 case Horde_Imap_Client::SORT_DISPLAYTO: 190 $field = ($val == Horde_Imap_Client::SORT_DISPLAYFROM) 191 ? 'from' 192 : 'to'; 193 194 foreach ($slice as $num) { 195 $env = $fetch_res[$num]->getEnvelope(); 196 197 if (empty($env->$field)) { 198 $sorted[$num] = null; 199 } else { 200 $addr_ob = reset($env->$field); 201 if (is_null($sorted[$num] = $addr_ob->personal)) { 202 $sorted[$num] = $addr_ob->mailbox; 203 } 204 } 205 } 206 207 asort($sorted, SORT_LOCALE_STRING); 208 break; 209 210 case Horde_Imap_Client::SORT_CC: 211 case Horde_Imap_Client::SORT_FROM: 212 case Horde_Imap_Client::SORT_TO: 213 if ($val == Horde_Imap_Client::SORT_CC) { 214 $field = 'cc'; 215 } elseif ($val == Horde_Imap_Client::SORT_FROM) { 216 $field = 'from'; 217 } else { 218 $field = 'to'; 219 } 220 221 foreach ($slice as $num) { 222 $tmp = $fetch_res[$num]->getEnvelope()->$field; 223 $sorted[$num] = count($tmp) 224 ? $tmp[0]->mailbox 225 : null; 226 } 227 asort($sorted, SORT_LOCALE_STRING); 228 break; 229 230 case Horde_Imap_Client::SORT_ARRIVAL: 231 $sorted = $this->_getSentDates($fetch_res, $slice, true); 232 asort($sorted, SORT_NUMERIC); 233 break; 234 235 case Horde_Imap_Client::SORT_DATE: 236 // Date sorting rules in RFC 5256 [2.2] 237 $sorted = $this->_getSentDates($fetch_res, $slice); 238 asort($sorted, SORT_NUMERIC); 239 break; 240 241 case Horde_Imap_Client::SORT_SUBJECT: 242 // Subject sorting rules in RFC 5256 [2.1] 243 foreach ($slice as $num) { 244 $sorted[$num] = strval(new Horde_Imap_Client_Data_BaseSubject($fetch_res[$num]->getEnvelope()->subject)); 245 } 246 asort($sorted, SORT_LOCALE_STRING); 247 break; 248 } 249 250 // At this point, keys of $sorted are sequence/UID and values 251 // are the sort strings 252 if (!empty($sorted)) { 253 if (count($sorted) === count($res)) { 254 $res = array_keys($sorted); 255 } else { 256 array_splice($res, $slice_start, count($slice), array_keys($sorted)); 257 } 258 259 // Check for ties. 260 $last = $start = null; 261 $i = 0; 262 reset($sorted); 263 while (list($k, $v) = each($sorted)) { 264 if (is_null($last) || ($last != $v)) { 265 if ($i) { 266 $slices[array_search($start, $res)] = array_slice($sorted, array_search($start, $sorted), $i + 1); 267 $i = 0; 268 } 269 $last = $v; 270 $start = $k; 271 } else { 272 ++$i; 273 } 274 } 275 if ($i) { 276 $slices[array_search($start, $res)] = array_slice($sorted, array_search($start, $sorted), $i + 1); 277 } 278 } 279 } 280 281 $reverse = false; 282 } 283 284 return $res; 285 } 286 287 /** 288 * Get the sent dates for purposes of SORT/THREAD sorting under RFC 5256 289 * [2.2]. 290 * 291 * @param Horde_Imap_Client_Fetch_Results $data Data returned from 292 * fetch() that includes 293 * both date and envelope 294 * items. 295 * @param array $ids The IDs to process. 296 * @param boolean $internal Only use internal date? 297 * 298 * @return array A mapping of IDs -> UNIX timestamps. 299 */ 300 protected function _getSentDates(Horde_Imap_Client_Fetch_Results $data, 301 $ids, $internal = false) 302 { 303 $dates = array(); 304 305 foreach ($ids as $num) { 306 $dt = ($internal || !isset($data[$num]->getEnvelope()->date)) 307 // RFC 5256 [3] & 3501 [6.4.4]: disregard timezone when 308 // using internaldate. 309 ? $data[$num]->getImapDate() 310 : $data[$num]->getEnvelope()->date; 311 $dates[$num] = $dt->format('U'); 312 } 313 314 return $dates; 315 } 316 317 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |