1<?php
2
3/**
4 * Core modules
5 * @package modules
6 * @subpackage core
7 */
8
9/**
10 * get basic message list settings
11 * @subpackage core/functions
12 * @param string $path message list path
13 * @param object $handler hm handler module
14 * @return array
15 */
16if (!hm_exists('get_message_list_settings')) {
17function get_message_list_settings($path, $handler) {
18    $list_path = $path;
19    $mailbox_list_title = array();
20    $message_list_since = DEFAULT_SINCE;
21    $per_source_limit = DEFAULT_PER_SOURCE;
22
23    if ($path == 'unread') {
24        $list_path = 'unread';
25        $mailbox_list_title = array('Unread');
26        $message_list_since = $handler->user_config->get('unread_since_setting', DEFAULT_SINCE);
27        $per_source_limit = $handler->user_config->get('unread_per_source_setting', DEFAULT_PER_SOURCE);
28    }
29    elseif ($path == 'email') {
30        $message_list_since = $handler->user_config->get('all_email_since_setting', DEFAULT_SINCE);
31        $per_source_limit = $handler->user_config->get('all_email_per_source_setting', DEFAULT_PER_SOURCE);
32        $list_path = 'email';
33        $mailbox_list_title = array('All Email');
34    }
35    elseif ($path == 'flagged') {
36        $list_path = 'flagged';
37        $message_list_since = $handler->user_config->get('flagged_since_setting', DEFAULT_SINCE);
38        $per_source_limit = $handler->user_config->get('flagged_per_source_setting', DEFAULT_PER_SOURCE);
39        $mailbox_list_title = array('Flagged');
40    }
41    elseif ($path == 'combined_inbox') {
42        $list_path = 'combined_inbox';
43        $message_list_since = $handler->user_config->get('all_since_setting', DEFAULT_SINCE);
44        $per_source_limit = $handler->user_config->get('all_per_source_setting', DEFAULT_PER_SOURCE);
45        $mailbox_list_title = array('Everything');
46    }
47    return array($list_path, $mailbox_list_title, $message_list_since, $per_source_limit);
48}}
49
50/**
51 * Build meta information for a message list
52 * @subpackage core/functions
53 * @param array $input module output
54 * @param object $output_mod Hm_Output_Module
55 * @return string
56 */
57if (!hm_exists('message_list_meta')) {
58function message_list_meta($input, $output_mod) {
59    if (!array_key_exists('list_meta', $input) || !$input['list_meta']) {
60        return '';
61    }
62    $limit = 0;
63    $since = false;
64    $times = array(
65        'today' => 'Today',
66        '-1 week' => 'Last 7 days',
67        '-2 weeks' => 'Last 2 weeks',
68        '-4 weeks' => 'Last 4 weeks',
69        '-6 weeks' => 'Last 6 weeks',
70        '-6 months' => 'Last 6 months',
71        '-1 year' => 'Last year',
72        '-5 years' => 'Last 5 years'
73    );
74    if (array_key_exists('per_source_limit', $input)) {
75        $limit = $input['per_source_limit'];
76    }
77    if (!$limit) {
78        $limit = DEFAULT_PER_SOURCE;
79    }
80    if (array_key_exists('message_list_since', $input)) {
81        $since = $input['message_list_since'];
82    }
83    if (!$since) {
84        $since = DEFAULT_SINCE;
85    }
86    $date = sprintf('%s', strtolower($output_mod->trans($times[$since])));
87    $max = sprintf($output_mod->trans('sources@%d each'), $limit);
88
89    return '<div class="list_meta">'.
90        $date.
91        '<b>-</b>'.
92        '<span class="src_count"></span> '.$max.
93        '<b>-</b>'.
94        '<span class="total"></span> '.$output_mod->trans('total').'</div>';
95}}
96
97/**
98 * Build sort dialog for a combined list
99 * @subpackage core/functions
100 * @param object $output_mod Hm_Output_Module
101 * @return string
102 */
103if (!hm_exists('combined_sort_dialog')) {
104function combined_sort_dialog($mod) {
105    $sorts = array(
106        '4' => $mod->trans('Arrival'),
107        '2' => $mod->trans('From'),
108        '3' => $mod->trans('Subject'),
109    );
110
111    $res = '<select name="sort" class="combined_sort">';
112    foreach ($sorts as $name => $val) {
113        $res .= '<option value="'.$name.'">'.$val.' &darr;</option>';
114        $res .= '<option value="-'.$name.'">'.$val.' &uarr;</option>';
115    }
116    $res .= '</select>';
117    return $res;
118}}
119
120/**
121 * Build a human readable interval string
122 * @subpackage core/functions
123 * @param string $date_str date string parsable by strtotime()
124 * @return string
125 */
126if (!hm_exists('human_readable_interval')) {
127function human_readable_interval($date_str) {
128    $precision     = 2;
129    $interval_time = array();
130    $date          = strtotime($date_str);
131    $interval      = time() - $date;
132    $res           = array();
133
134    $t['second'] = 1;
135    $t['minute'] = $t['second']*60;
136    $t['hour']   = $t['minute']*60;
137    $t['day']    = $t['hour']*24;
138    $t['week']   = $t['day']*7;
139    $t['month']  = $t['day']*30;
140    $t['year']   = $t['week']*52;
141
142    if ($interval < 0) {
143        return 'From the future!';
144    }
145    elseif ($interval == 0) {
146        return 'Just now';
147    }
148    foreach (array_reverse($t) as $name => $val) {
149        if ($interval_time[$name] = ($interval/$val > 0) ? floor($interval/$val) : false) {
150            $interval -= $val*$interval_time[$name];
151        }
152    }
153    $interval_time = array_slice(array_filter($interval_time, function($v) { return $v > 0; }), 0, $precision);
154    foreach($interval_time as $name => $val) {
155        if ($val > 1) {
156            $res[] = sprintf('%d %ss', $val, $name);
157        }
158        else {
159            $res[] = sprintf('%d %s', $val, $name);
160        }
161    }
162    return implode(', ', $res);
163}}
164
165/**
166 * Output a message list row of data using callbacks
167 * @subpackage core/functions
168 * @param array $values data and callbacks for each cell
169 * @param string $id unique id for the message
170 * @param string $style message list style (news or email)
171 * @param object $output_mod Hm_Output_Module
172 * @param string $row_class optional table row css class
173 * @return array
174 */
175if (!hm_exists('message_list_row')) {
176function message_list_row($values, $id, $style, $output_mod, $row_class='') {
177    $res = '<tr class="'.$output_mod->html_safe($id);
178    if ($row_class) {
179        $res .= ' '.$output_mod->html_safe($row_class);
180    }
181    $res .= '">';
182    if ($style == 'news') {
183        $res .= '<td class="news_cell checkbox_cell">';
184    }
185    foreach ($values as $vals) {
186        if (function_exists($vals[0])) {
187            $function = array_shift($vals);
188            $res .= $function($vals, $style, $output_mod);
189        }
190    }
191    if ($style == 'news') {
192        $res .= '</td>';
193    }
194    $res .= '</tr>';
195    return array($res, $id);
196}}
197
198/**
199 * Generic callback for a message list table cell
200 * @subpackage core/functions
201 * @param array $vals data for the cell
202 * @param string $style message list style
203 * @param object $output_mod Hm_Output_Module
204 * @return string
205 */
206if (!hm_exists('safe_output_callback')) {
207function safe_output_callback($vals, $style, $output_mod) {
208    $img = '';
209    if (count($vals) == 3 && $vals[2]) {
210        $img = '<img src="'.Hm_Image_Sources::${$vals[2]}.'" />';
211    }
212    if ($style == 'news') {
213        return sprintf('<div class="%s" title="%s">%s%s</div>', $output_mod->html_safe($vals[0]), $output_mod->html_safe($vals[1]), $img, $output_mod->html_safe($vals[1]));
214    }
215    return sprintf('<td class="%s" title="%s">%s%s</td>', $output_mod->html_safe($vals[0]), $output_mod->html_safe($vals[1]), $img, $output_mod->html_safe($vals[1]));
216}}
217
218/**
219 * Callback for a message list checkbox
220 * @subpackage core/functions
221 * @param array $vals data for the cell
222 * @param string $style message list style
223 * @param object $output_mod Hm_Output_Module
224 * @return string
225 */
226if (!hm_exists('checkbox_callback')) {
227function checkbox_callback($vals, $style, $output_mod) {
228    if ($style == 'news') {
229        return sprintf('<input type="checkbox" id="%s" value="%s" />'.
230            '<label class="checkbox_label" for="%s"></label>'.
231            '</td><td class="news_cell">', $output_mod->html_safe($vals[0]),
232            $output_mod->html_safe($vals[0]), $output_mod->html_safe($vals[0]));
233    }
234    return sprintf('<td class="checkbox_cell">'.
235        '<input id="'.$output_mod->html_safe($vals[0]).'" type="checkbox" value="%s" />'.
236        '<label class="checkbox_label" for="'.$output_mod->html_safe($vals[0]).'"></label>'.
237        '</td>', $output_mod->html_safe($vals[0]));
238}}
239
240/**
241 * Callback for a subject cell in a message list
242 * @subpackage core/functions
243 * @param array $vals data for the cell
244 * @param string $style message list style
245 * @param object $output_mod Hm_Output_Module
246 * @return string
247 */
248if (!hm_exists('subject_callback')) {
249function subject_callback($vals, $style, $output_mod) {
250    $img = '';
251    if (count($vals) == 4 && $vals[3]) {
252        $img = '<img alt="'.$output_mod->trans('list item').'" src="'.Hm_Image_Sources::${$vals[3]}.'" />';
253    }
254    $subject = $output_mod->html_safe($vals[0]);
255    $hl_subject = preg_replace("/^(\[[^\]]+\])/", '<span class="s_pre">$1</span>', $subject);
256    if ($style == 'news') {
257        return sprintf('<div class="subject"><div class="%s" title="%s">%s <a href="%s">%s</a></div></div>', $output_mod->html_safe(implode(' ', $vals[2])), $subject, $img, $output_mod->html_safe($vals[1]), $hl_subject);
258    }
259    return sprintf('<td class="subject"><div class="%s"><a title="%s" href="%s">%s</a></div></td>', $output_mod->html_safe(implode(' ', $vals[2])), $subject, $output_mod->html_safe($vals[1]), $hl_subject);
260}}
261
262/**
263 * Callback for a date cell in a message list
264 * @subpackage core/functions
265 * @param array $vals data for the cell
266 * @param string $style message list style
267 * @param object $output_mod Hm_Output_Module
268 * @return string
269 */
270if (!hm_exists('date_callback')) {
271function date_callback($vals, $style, $output_mod) {
272    if ($style == 'news') {
273        return sprintf('<div class="msg_date">%s<input type="hidden" class="msg_timestamp" value="%s" /></div>', $output_mod->html_safe($vals[0]), $output_mod->html_safe($vals[1]));
274    }
275    return sprintf('<td class="msg_date" title="%s">%s<input type="hidden" class="msg_timestamp" value="%s" /></td>', $output_mod->html_safe(date('r', $vals[1])), $output_mod->html_safe($vals[0]), $output_mod->html_safe($vals[1]));
276}}
277
278/**
279 * Callback for an icon in a message list row
280 * @subpackage core/functions
281 * @param array $vals data for the cell
282 * @param string $style message list style
283 * @param object $output_mod Hm_Output_Module
284 * @return string
285 */
286if (!hm_exists('icon_callback')) {
287function icon_callback($vals, $style, $output_mod) {
288    $icons = '';
289    $title = array();
290    $show_icons = $output_mod->get('msg_list_icons');
291    if (in_array('flagged', $vals[0])) {
292        $icons .= $show_icons ? '<img src="'.Hm_Image_Sources::$star.'" width="16" height="16" alt="'.$output_mod->trans('Flagged').'" />' : ' F';
293        $title[] = $output_mod->trans('Flagged');
294    }
295    if (in_array('answered', $vals[0])) {
296        $icons .= $show_icons ? '<img src="'.Hm_Image_Sources::$circle_check.'" width="16" height="16" alt="'.$output_mod->trans('Answered').'" />' : ' A';
297        $title[] = $output_mod->trans('Answered');
298    }
299    if (in_array('attachment', $vals[0])) {
300        $icons .= $show_icons ? '<img src="'.Hm_Image_Sources::$paperclip.'" width="16" height="16" alt="'.$output_mod->trans('Attachment').'" />' : ' +';
301        $title[] = $output_mod->trans('Attachment');
302    }
303    $title = implode(', ', $title);
304    if ($style == 'news') {
305        return sprintf('<div class="icon" title="%s">%s</div>', $title, $icons);
306    }
307    return sprintf('<td class="icon" title="%s">%s</td>', $title, $icons);
308}}
309
310/**
311 * Output message controls
312 * @subpackage core/functions
313 * @param object $output_mod Hm_Output_Module
314 * @return string
315 */
316if (!hm_exists('message_controls')) {
317function message_controls($output_mod) {
318    $res = '<a class="toggle_link" href="#"><img alt="x" src="'.Hm_Image_Sources::$check.'" width="8" height="8" /></a>'.
319        '<div class="msg_controls">'.
320        '<a class="msg_read core_msg_control" href="#" data-action="read">'.$output_mod->trans('Read').'</a>'.
321        '<a class="msg_unread core_msg_control" href="#" data-action="unread">'.$output_mod->trans('Unread').'</a>'.
322        '<a class="msg_flag core_msg_control" href="#" data-action="flag">'.$output_mod->trans('Flag').'</a>'.
323        '<a class="msg_unflag core_msg_control" href="#" data-action="unflag">'.$output_mod->trans('Unflag').'</a>'.
324        '<a class="msg_delete core_msg_control" href="#" data-action="delete">'.$output_mod->trans('Delete').'</a>';
325    if ($output_mod->get('msg_controls_extra')) {
326        $res .= $output_mod->get('msg_controls_extra');
327    }
328    $res .= '</div>';
329    return $res;
330}}
331
332/**
333 * Output select element for "received since" options
334 * @subpackage core/functions
335 * @param string $since current value to pre-select
336 * @param string $name name used as the elements id and name
337 * @param object $output_mod Hm_Output_Module
338 * @return string
339 */
340if (!hm_exists('message_since_dropdown')) {
341function message_since_dropdown($since, $name, $output_mod) {
342    $times = array(
343        'today' => 'Today',
344        '-1 week' => 'Last 7 days',
345        '-2 weeks' => 'Last 2 weeks',
346        '-4 weeks' => 'Last 4 weeks',
347        '-6 weeks' => 'Last 6 weeks',
348        '-6 months' => 'Last 6 months',
349        '-1 year' => 'Last year',
350        '-5 years' => 'Last 5 years'
351    );
352    $res = '<select name="'.$name.'" id="'.$name.'" class="message_list_since">';
353    foreach ($times as $val => $label) {
354        $res .= '<option';
355        if ($val == $since) {
356            $res .= ' selected="selected"';
357        }
358        $res .= ' value="'.$val.'">'.$output_mod->trans($label).'</option>';
359    }
360    $res .= '</select>';
361    return $res;
362}}
363
364/**
365 * Output a source list for a message list
366 * @subpackage core/functions
367 * @param array $sources source of the list
368 * @param object $output_mod Hm_Output_Module
369 */
370if (!hm_exists('list_sources')) {
371function list_sources($sources, $output_mod) {
372    $res = '<div class="list_sources">';
373    $res .= '<div class="src_title">'.$output_mod->html_safe('Sources').'</div>';
374    foreach ($sources as $src) {
375        if (array_key_exists('group', $src) && $src['group'] == 'background') {
376            continue;
377        }
378        if (array_key_exists('nodisplay', $src) && $src['nodisplay']) {
379            continue;
380        }
381        if ($src['type'] == 'imap' && !array_key_exists('folder', $src)) {
382            $folder = '_INBOX';
383        }
384        elseif (!array_key_exists('folder', $src)) {
385            $folder = '';
386        }
387        else {
388            $folder = '_'.hex2bin($src['folder']);
389        }
390        $res .= '<div class="list_src">'.$output_mod->html_safe($src['type']).' '.$output_mod->html_safe($src['name']);
391        $res .= ' '.$output_mod->html_safe(str_replace('_', '', $folder));
392        $res .= '</div>';
393    }
394    $res .= '</div>';
395    return $res;
396}}
397
398/**
399 * Output message list controls
400 * @subpackage core/functions
401 * @param string $refresh_link refresh link tag
402 * @param string $config_link configuration link tag
403 * @param string $source_link source link tag
404 * @return string
405 */
406if (!hm_exists('list_controls')) {
407function list_controls($refresh_link, $config_link, $source_link=false) {
408    return '<div class="list_controls">'.
409        $refresh_link.$source_link.$config_link.'</div>';
410}}
411
412/**
413 * Validate search terms
414 * @subpackage core/functions
415 * @param string $terms search terms to validate
416 * @return string
417 */
418if (!hm_exists('validate_search_terms')) {
419function validate_search_terms($terms) {
420    $terms = trim(strip_tags($terms));
421    if (!$terms) {
422        $terms = '';
423    }
424    return $terms;
425}}
426
427/**
428 * Validate the name of a search field
429 * @subpackage core/functions
430 * @param string $fld name to validate
431 * @return mixed
432 */
433if (!hm_exists('validate_search_fld')) {
434function validate_search_fld($fld) {
435    if (in_array($fld, array('TEXT', 'BODY', 'FROM', 'SUBJECT'))) {
436        return $fld;
437    }
438    return false;
439}}
440
441/**
442 * Output a select element for the search field
443 * @subpackage core/functions
444 * @param string $current currently selected field
445 * @param object $output_mod Hm_Output_Module
446 * @return string
447 */
448if (!hm_exists('search_field_selection')) {
449function search_field_selection($current, $output_mod) {
450    $flds = array(
451        'TEXT' => 'Entire message',
452        'BODY' => 'Message body',
453        'SUBJECT' => 'Subject',
454        'FROM' => 'From',
455    );
456    $res = '<select id="search_fld" name="search_fld">';
457    foreach ($flds as $val => $name) {
458        $res .= '<option ';
459        if ($current == $val) {
460            $res .= 'selected="selected" ';
461        }
462        $res .= 'value="'.$val.'">'.$output_mod->trans($name).'</option>';
463    }
464    $res .= '</select>';
465    return $res;
466}}
467
468/**
469 * Build pagination links for a list of messages
470 * @subpackage core/functions
471 * @param int $page_size number of messages per page
472 * @param int $current current page number
473 * @param int $total number of messages total
474 * @param string $path list path
475 * @param string $filter list filter
476 * @param string $sort list sort
477 * @return string
478 */
479if (!hm_exists('build_page_links')) {
480function build_page_links($page_size, $current_page, $total, $path, $filter=false, $sort=false) {
481    $links = '';
482    $first = '';
483    $last = '';
484    $display_links = 10;
485    if ($filter) {
486        $filter_str = '&amp;filter='.$filter;
487    }
488    else {
489        $filter_str = '';
490    }
491    if ($sort) {
492        $sort_str = '&amp;sort='.$sort;
493    }
494    else {
495        $sort_str = '';
496    }
497
498    $max_pages = ceil($total/$page_size);
499    if ($max_pages == 1) {
500        return '';
501    }
502    $floor = ($current_page - 1) - intval($display_links/2);
503    if ($floor < 0) {
504        $floor = 1;
505    }
506    $ceil = $floor + $display_links;
507    if ($ceil > $max_pages) {
508        $floor -= ($ceil - $max_pages);
509    }
510    $prev = '<a class="disabled_link"><img src="'.Hm_Image_Sources::$caret_left.'" alt="&larr;" /></a>';
511    $next = '<a class="disabled_link"><img src="'.Hm_Image_Sources::$caret_right.'" alt="&rarr;" /></a>';
512
513    if ($floor > 1 ) {
514        $first = '<a href="?page=message_list&amp;list_path='.urlencode($path).'&amp;list_page=1'.$filter_str.$sort_str.'">1</a> ... ';
515    }
516    if ($ceil < $max_pages) {
517        $last = ' ... <a href="?page=message_list&amp;list_path='.urlencode($path).'&amp;list_page='.$max_pages.$filter_str.$sort_str.'">'.$max_pages.'</a>';
518    }
519    if ($current_page > 1) {
520        $prev = '<a href="?page=message_list&amp;list_path='.urlencode($path).'&amp;list_page='.($current_page - 1).$filter_str.$sort_str.'"><img src="'.Hm_Image_Sources::$caret_left.'" alt="&larr;" /></a>';
521    }
522    if ($max_pages > 1 && $current_page < $max_pages) {
523        $next = '<a href="?page=message_list&amp;list_path='.urlencode($path).'&amp;list_page='.($current_page + 1).$filter_str.$sort_str.'"><img src="'.Hm_Image_Sources::$caret_right.'" alt="&rarr;" /></a>';
524    }
525    for ($i=1;$i<=$max_pages;$i++) {
526        if ($i < $floor || $i > $ceil) {
527            continue;
528        }
529        $links .= ' <a ';
530        if ($i == $current_page) {
531            $links .= 'class="current_page" ';
532        }
533        $links .= 'href="?page=message_list&amp;list_path='.urlencode($path).'&amp;list_page='.$i.$filter_str.$sort_str.'">'.$i.'</a>';
534    }
535    return $prev.' '.$first.$links.$last.' '.$next;
536}}
537
538