1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15: class IMP_Views_ListMessages
16: {
17:
18: const IDX_SEP = "\0";
19:
20: 21: 22: 23: 24:
25: protected $_flaghook = true;
26:
27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
43: public function listMessages($args)
44: {
45: global $injector;
46:
47: $initial = $args['initial'];
48: $is_search = false;
49: $mbox = IMP_Mailbox::get($args['mbox']);
50: $sortpref = $mbox->getSort();
51:
52:
53: if (strlen($args['qsearchmbox'])) {
54: $qsearch_mbox = IMP_Mailbox::formFrom($args['qsearchmbox']);
55:
56: if (strlen($args['qsearchfilter'])) {
57: $injector->getInstance('IMP_Search')->applyFilter($args['qsearchfilter'], array($qsearch_mbox), $mbox);
58: $is_search = true;
59: } else {
60:
61: $c_list = array();
62:
63: if (strlen($args['qsearchflag'])) {
64: $c_list[] = new IMP_Search_Element_Flag(
65: $args['qsearchflag'],
66: empty($args['qsearchflagnot'])
67: );
68:
69: $is_search = true;
70: } elseif (strlen($args['qsearch'])) {
71: $GLOBALS['prefs']->setValue('dimp_qsearch_field', $args['qsearchfield']);
72: $is_search = true;
73:
74: switch ($args['qsearchfield']) {
75: case 'all':
76: case 'body':
77: $c_list[] = new IMP_Search_Element_Text(
78: $args['qsearch'],
79: ($args['qsearchfield'] == 'body')
80: );
81: break;
82:
83: case 'from':
84: case 'subject':
85: $c_list[] = new IMP_Search_Element_Header(
86: $args['qsearch'],
87: $args['qsearchfield']
88: );
89: break;
90:
91: case 'recip':
92: $c_list[] = new IMP_Search_Element_Recipient(
93: $args['qsearch']
94: );
95: break;
96:
97: default:
98: $is_search = false;
99: break;
100: }
101: }
102:
103:
104: if ($is_search) {
105: $injector->getInstance('IMP_Search')->createQuery($c_list, array(
106: 'id' => $mbox,
107: 'mboxes' => array($qsearch_mbox),
108: 'type' => IMP_Search::CREATE_QUERY
109: ));
110: }
111: }
112: } else {
113: $is_search = $mbox->search;
114: }
115:
116:
117: $GLOBALS['registry']->setTimeZone();
118:
119:
120: if (!empty($args['applyfilter'])) {
121: $mbox->filter();
122: } elseif ($mbox->inbox) {
123: $mbox->filterOnDisplay();
124: }
125:
126:
127: $mailbox_list = $mbox->getListOb();
128: $msgcount = count($mailbox_list);
129:
130:
131: $result = $this->getBaseOb($mbox);
132: $result->cacheid = $mbox->cacheid_date;
133: if (!empty($args['requestid'])) {
134: $result->requestid = intval($args['requestid']);
135: }
136: $result->totalrows = $msgcount;
137: if (!$args['initial']) {
138: unset($result->label);
139: }
140:
141: $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
142:
143: 144: 145:
146: $parsed = null;
147: if ($args['cacheid'] && $args['cache']) {
148: $uid_expire = false;
149: $parsed = $imp_imap->parseCacheId($args['cacheid']);
150:
151: if ($parsed['date'] != date('mdy')) {
152: $uid_expire = true;
153: } elseif (!$is_search) {
154: try {
155: $status = $imp_imap->status($mbox, Horde_Imap_Client::STATUS_UIDVALIDITY);
156: $uid_expire = ($parsed['uidvalidity'] != $status['uidvalidity']);
157: } catch (Horde_Imap_Cache_Exception $e) {
158: $uid_expire = true;
159: }
160: }
161:
162: if ($uid_expire) {
163: $args['cache'] = array();
164: $args['initial'] = true;
165: $result->data_reset = $result->metadata_reset = 1;
166: }
167: }
168:
169:
170: $md = &$result->metadata;
171: if (($args['initial'] ||
172: $args['delhide'] ||
173: !is_null($args['sortby'])) &&
174: $mbox->hideDeletedMsgs(true)) {
175: $md->delhide = 1;
176: }
177: if ($args['initial'] || !is_null($args['sortby'])) {
178: $md->sortby = intval($sortpref['by']);
179: }
180: if ($args['initial'] || !is_null($args['sortdir'])) {
181: $md->sortdir = intval($sortpref['dir']);
182: }
183: if ($args['initial'] && $sortpref['locked']) {
184: $md->sortlock = 1;
185: }
186:
187:
188: if ($args['initial']) {
189: if (!$mbox->access_sortthread) {
190: $md->nothread = 1;
191: }
192: if ($mbox->special_outgoing) {
193: $md->special = 1;
194: if ($mbox == IMP_Mailbox::getPref('drafts_folder')) {
195: $md->drafts = 1;
196: }
197: } elseif ($mbox == IMP_Mailbox::getPref('spam_folder')) {
198: $md->spam = 1;
199: }
200:
201: if ($is_search) {
202: $md->search = 1;
203: }
204:
205:
206: $flaglist = $injector->getInstance('IMP_Flags')->getList(array(
207: 'imap' => true,
208: 'mailbox' => $is_search ? null : $mbox
209: ));
210:
211: $md->flags = array();
212: foreach ($flaglist as $val) {
213: $md->flags[] = $val->imapflag;
214: }
215: }
216:
217:
218: if ($is_search &&
219: ($args['initial'] || strlen($args['qsearchmbox']))) {
220: $imp_search = $injector->getInstance('IMP_Search');
221:
222: if ($mbox->vfolder) {
223: $md->slabel = $imp_search[$mbox]->label;
224: $md->vfolder = 1;
225: if (!$imp_search->isVFolder($mbox, true)) {
226: $md->noedit = 1;
227: }
228: } else {
229: $md->slabel = $imp_search[$mbox]->querytext;
230: }
231: }
232:
233: 234:
235: $md->readonly = intval($mbox->readonly);
236: if (!$md->readonly) {
237: if (!$mbox->access_deletemsgs) {
238: $md->nodelete = 1;
239: }
240: if (!$mbox->access_expunge) {
241: $md->noexpunge = 1;
242: }
243: }
244:
245: 246: 247:
248: if (empty($msgcount) && !$is_search) {
249: if (!$mbox->exists) {
250: $GLOBALS['notification']->push(sprintf(_("Mailbox %s does not exist."), $mbox->label), 'horde.error');
251: }
252:
253: if (!empty($args['change'])) {
254: unset($result->data, $result->rowlist, $result->totalrows);
255: $result->data_reset = $result->rowlist_reset = 1;
256: }
257:
258: return $result;
259: }
260:
261: 262: 263:
264: if (!isset($result->data_reset) && !empty($args['change'])) {
265: $result->rowlist_reset = 1;
266: }
267:
268:
269: $cached = array();
270: if (!empty($args['cache'])) {
271: foreach ($imp_imap->getUtils()->fromSequenceString($args['cache']) as $key => $uids) {
272: $key = IMP_Mailbox::formFrom($key);
273:
274: foreach ($uids as $val) {
275: $cached[] = $is_search
276: ? $this->searchUid($key, $val)
277: : $val;
278: }
279: }
280: $cached = array_flip($cached);
281: }
282:
283: if (!empty($args['search_unseen'])) {
284: 285: 286:
287: $unseen_search = $mailbox_list->unseenMessages(Horde_Imap_Client::SORT_RESULTS_MATCH, true);
288: if (!($uid_search = array_diff($unseen_search['match']->ids, array_keys($cached)))) {
289: return $result;
290: }
291: $rownum = $mailbox_list->getArrayIndex(reset($uid_search));
292: } elseif (!empty($args['search_uid'])) {
293: $rownum = $mailbox_list->getArrayIndex($args['search_uid'], $mbox);
294: }
295:
296: 297:
298: $rownum = ($initial || (isset($rownum) && is_null($rownum)))
299: ? intval($mailbox_list->mailboxStart($msgcount))
300: : null;
301:
302:
303: if (is_null($rownum)) {
304: $slice_start = $args['slice_start'];
305: $slice_end = $args['slice_end'];
306: } else {
307: $slice_start = $rownum - $args['before'];
308: $slice_end = $rownum + $args['after'];
309: if ($slice_start < 1) {
310: $slice_end += abs($slice_start) + 1;
311: } elseif ($slice_end > $msgcount) {
312: $slice_start -= $slice_end - $msgcount;
313: }
314:
315: $result->rownum = $rownum;
316: }
317:
318: $slice_start = max(1, $slice_start);
319: $slice_end = min($msgcount, $slice_end);
320:
321:
322: $changed = $data = $msglist = $rowlist = $uidlist = array();
323: foreach ($mailbox_list as $key => $val) {
324: $uidlist[] = $is_search
325: ? $this->searchUid($val['m'], $val['u'])
326: : $val['u'];
327: }
328:
329: 330: 331:
332: if (!empty($cached) && isset($result->rowlist_reset)) {
333: $disappear = array();
334: foreach (array_diff(array_keys($cached), $uidlist) as $uid) {
335: $disappear[] = $uid;
336: unset($cached[$uid]);
337: }
338: if (!empty($disappear)) {
339: $result->disappear = $disappear;
340: }
341: }
342:
343: 344: 345:
346: if (!empty($cached) &&
347: !$is_search &&
348: !is_null($parsed) &&
349: !empty($parsed['highestmodseq'])) {
350: $status = $imp_imap->status($mbox, Horde_Imap_Client::STATUS_LASTMODSEQ | Horde_Imap_Client::STATUS_LASTMODSEQUIDS);
351: if ($status['lastmodseq'] == $parsed['highestmodseq']) {
352: 353: 354:
355: $changed = array_flip($status['lastmodsequids']);
356: } else {
357: $query = new Horde_Imap_Client_Fetch_Query();
358: $query->uid();
359:
360: try {
361: $changed = $imp_imap->fetch($mbox, $query, array(
362: 'changedsince' => $parsed['highestmodseq'],
363: 'ids' => $imp_imap->getIdsOb(array_keys($cached))
364: ));
365: } catch (IMP_Imap_Exception $e) {}
366: }
367: }
368:
369: foreach (array_slice($uidlist, $slice_start - 1, $slice_end - $slice_start + 1, true) as $key => $uid) {
370: $seq = ++$key;
371: $msglist[$seq] = $mailbox_list[$seq]['u'];
372: $rowlist[$uid] = $seq;
373: 374:
375: if (!isset($cached[$uid]) || isset($changed[$uid])) {
376: $data[$seq] = 1;
377: }
378: }
379: $result->rowlist = $rowlist;
380:
381:
382: if ($args['rangeslice']) {
383: $slice = new stdClass;
384: $slice->rangelist = array_keys($rowlist);
385: $slice->view = $mbox->form_to;
386:
387: return $slice;
388: }
389:
390:
391: $result->data = $this->_getOverviewData($mbox, array_keys($data));
392:
393:
394: if (!$is_search &&
395: ($sortpref['by'] == Horde_Imap_Client::SORT_THREAD)) {
396: $imp_thread = new IMP_Imap_Thread($mailbox_list->getThreadOb());
397: $md->thread = (object)$imp_thread->getThreadTreeOb($msglist, $sortpref['dir']);
398: }
399:
400: return $result;
401: }
402:
403: 404: 405: 406: 407: 408: 409: 410: 411: 412:
413: private function _getOverviewData($mbox, $msglist)
414: {
415: $msgs = array();
416:
417: if (empty($msglist)) {
418: return $msgs;
419: }
420:
421:
422: $overview = $mbox->getListOb()->getMailboxArray($msglist, array(
423: 'headers' => true,
424: 'type' => $GLOBALS['prefs']->getValue('atc_flag')
425: ));
426: $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
427: $imp_ui = new IMP_Ui_Mailbox($mbox);
428:
429: $flags = $imp_imap->access(IMP_Imap::ACCESS_FLAGS);
430: $pop3 = $imp_imap->pop3;
431: $search = $mbox->search;
432:
433:
434: reset($overview['overview']);
435: while (list(,$ob) = each($overview['overview'])) {
436:
437: $msg = array(
438: 'flag' => array(),
439: 'mbox' => IMP_Mailbox::formTo($ob['mailbox']),
440: 'uid' => ($pop3 ? $ob['uid'] : intval($ob['uid']))
441: );
442:
443:
444: if ($flags) {
445: if ($this->_flaghook) {
446: try {
447: $ob['flags'] = array_merge($ob['flags'], Horde::callHook('msglist_flags', array($ob, 'dimp'), 'imp'));
448: } catch (Horde_Exception_HookNotSet $e) {
449: $this->_flaghook = false;
450: }
451: }
452:
453: $flag_parse = $GLOBALS['injector']->getInstance('IMP_Flags')->parse(array(
454: 'flags' => $ob['flags'],
455: 'headers' => $ob['headers'],
456: 'personal' => Horde_Mime_Address::getAddressesFromObject($ob['envelope']->to, array('charset' => 'UTF-8'))
457: ));
458:
459: foreach ($flag_parse as $val) {
460: $msg['flag'][] = $val->id;
461: }
462: }
463:
464:
465: $msg['size'] = htmlspecialchars($imp_ui->getSize($ob['size']), ENT_QUOTES, 'UTF-8');
466:
467:
468: $msg['date'] = htmlspecialchars($imp_ui->getDate($ob['envelope']->date), ENT_QUOTES, 'UTF-8');
469:
470:
471: $getfrom = $imp_ui->getFrom($ob['envelope'], array('specialchars' => 'UTF-8'));
472: $msg['from'] = $getfrom['from'];
473:
474:
475: $msg['subject'] = $imp_ui->getSubject($ob['envelope']->subject, true);
476:
477: 478: 479: 480:
481: if ($ob['headers']->getValue('list-post')) {
482: $msg['listmsg'] = 1;
483: }
484:
485: 486:
487: if ($search) {
488: $msgs[$this->searchUid($ob['mailbox'], $ob['uid'])] = $msg;
489: } else {
490: $msgs[$ob['uid']] = $msg;
491: }
492: }
493:
494:
495: try {
496: $msgs = Horde::callHook('mailboxarray', array($msgs, 'dimp'), 'imp');
497: } catch (Horde_Exception_HookNotSet $e) {}
498:
499: return $msgs;
500: }
501:
502: 503: 504: 505: 506: 507: 508:
509: public function getBaseOb(IMP_Mailbox $mbox)
510: {
511: $ob = new stdClass;
512: $ob->cacheid = 0;
513: $ob->data = array();
514: $ob->label = htmlspecialchars($mbox->label);
515: $ob->metadata = new stdClass;
516: $ob->rowlist = array();
517: $ob->totalrows = 0;
518: $ob->view = $mbox->form_to;
519:
520: return $ob;
521: }
522:
523: 524: 525: 526: 527: 528: 529: 530:
531: static public function searchUid($mbox, $uid)
532: {
533: return IMP::base64urlEncode(strval($mbox) . self::IDX_SEP . $uid);
534: }
535:
536: }
537: