source: subversion/trunk/roundcubemail/program/include/main.inc @ 1361

Last change on this file since 1361 was 1361, checked in by richs, 5 years ago

/tmp/out

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.6 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | program/include/main.inc                                              |
6 |                                                                       |
7 | This file is part of the RoundCube Webmail client                     |
8 | Copyright (C) 2005-2008, RoundCube Dev, - Switzerland                 |
9 | Licensed under the GNU GPL                                            |
10 |                                                                       |
11 | PURPOSE:                                                              |
12 |   Provide basic functions for the webmail package                     |
13 |                                                                       |
14 +-----------------------------------------------------------------------+
15 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16 +-----------------------------------------------------------------------+
17
18 $Id$
19
20*/
21
22/**
23 * RoundCube Webmail common functions
24 *
25 * @package Core
26 * @author Thomas Bruederli <roundcube@gmail.com>
27 */
28
29require_once('lib/utf7.inc');
30require_once('include/rcube_shared.inc');
31
32// fallback if not PHP modules are available
33@include_once('lib/des.inc');
34@include_once('lib/utf8.class.php');
35
36// define constannts for input reading
37define('RCUBE_INPUT_GET', 0x0101);
38define('RCUBE_INPUT_POST', 0x0102);
39define('RCUBE_INPUT_GPC', 0x0103);
40
41
42
43/**
44 * Return correct name for a specific database table
45 *
46 * @param string Table name
47 * @return string Translated table name
48 */
49function get_table_name($table)
50  {
51  global $CONFIG;
52
53  // return table name if configured
54  $config_key = 'db_table_'.$table;
55
56  if (strlen($CONFIG[$config_key]))
57    return $CONFIG[$config_key];
58
59  return $table;
60  }
61
62
63/**
64 * Return correct name for a specific database sequence
65 * (used for Postgres only)
66 *
67 * @param string Secuence name
68 * @return string Translated sequence name
69 */
70function get_sequence_name($sequence)
71  {
72  global $CONFIG;
73
74  // return table name if configured
75  $config_key = 'db_sequence_'.$sequence;
76
77  if (strlen($CONFIG[$config_key]))
78    return $CONFIG[$config_key];
79
80  return $sequence;
81  }
82
83
84/**
85 * Get localized text in the desired language
86 * It's a global wrapper for rcmail::gettext()
87 *
88 * @param mixed Named parameters array or label name
89 * @return string Localized text
90 * @see rcmail::gettext()
91 */
92function rcube_label($p)
93{
94  return rcmail::get_instance()->gettext($p);
95}
96
97
98/**
99 * Load virtuser table in array
100 *
101 * @return array Virtuser table entries
102 */
103function rcmail_getvirtualfile()
104  {
105  global $CONFIG;
106  if (empty($CONFIG['virtuser_file']) || !is_file($CONFIG['virtuser_file']))
107    return FALSE;
108 
109  // read file
110  $a_lines = file($CONFIG['virtuser_file']);
111  return $a_lines;
112  }
113
114
115/**
116 * Find matches of the given pattern in virtuser table
117 *
118 * @param string Regular expression to search for
119 * @return array Matching entries
120 */
121function rcmail_findinvirtual($pattern)
122  {
123  $result = array();
124  $virtual = rcmail_getvirtualfile();
125  if ($virtual==FALSE)
126    return $result;
127
128  // check each line for matches
129  foreach ($virtual as $line)
130    {
131    $line = trim($line);
132    if (empty($line) || $line{0}=='#')
133      continue;
134     
135    if (eregi($pattern, $line))
136      $result[] = $line;
137    }
138
139  return $result;
140  }
141
142
143/**
144 * Overwrite action variable
145 *
146 * @param string New action value
147 */
148function rcmail_overwrite_action($action)
149  {
150  $app = rcmail::get_instance();
151  $app->action = $action;
152  $app->output->set_env('action', $action);
153  }
154
155
156/**
157 * Compose an URL for a specific action
158 *
159 * @param string  Request action
160 * @param array   More URL parameters
161 * @param string  Request task (omit if the same)
162 * @return The application URL
163 */
164function rcmail_url($action, $p=array(), $task=null)
165{
166  $app = rcmail::get_instance();
167 
168  $qstring = '';
169  $base = $app->comm_path;
170 
171  if ($task && in_array($task, rcmail::$main_tasks))
172    $base = ereg_replace('_task=[a-z]+', '_task='.$task, $app->comm_path);
173 
174  if (is_array($p))
175    foreach ($p as $key => $val)
176      $qstring .= '&'.urlencode($key).'='.urlencode($val);
177 
178  return $base . ($action ? '&_action='.$action : '') . $qstring;
179}
180
181
182/**
183 * Add a localized label to the client environment
184 * @deprecated
185 */
186function rcube_add_label()
187  {
188  global $OUTPUT;
189 
190  $arg_list = func_get_args();
191  foreach ($arg_list as $i => $name)
192    $OUTPUT->add_label($name);
193  }
194
195
196/**
197 * Garbage collector function for temp files.
198 * Remove temp files older than two days
199 */
200function rcmail_temp_gc()
201  {
202  $tmp = unslashify($CONFIG['temp_dir']);
203  $expire = mktime() - 172800;  // expire in 48 hours
204
205  if ($dir = opendir($tmp))
206    {
207    while (($fname = readdir($dir)) !== false)
208      {
209      if ($fname{0} == '.')
210        continue;
211
212      if (filemtime($tmp.'/'.$fname) < $expire)
213        @unlink($tmp.'/'.$fname);
214      }
215
216    closedir($dir);
217    }
218  }
219
220
221/**
222 * Garbage collector for cache entries.
223 * Remove all expired message cache records
224 */
225function rcmail_message_cache_gc()
226  {
227  global $DB, $CONFIG;
228 
229  // no cache lifetime configured
230  if (empty($CONFIG['message_cache_lifetime']))
231    return;
232 
233  // get target timestamp
234  $ts = get_offset_time($CONFIG['message_cache_lifetime'], -1);
235 
236  $DB->query("DELETE FROM ".get_table_name('messages')."
237             WHERE  created < ".$DB->fromunixtime($ts));
238  }
239
240
241/**
242 * Convert a string from one charset to another.
243 * Uses mbstring and iconv functions if possible
244 *
245 * @param  string Input string
246 * @param  string Suspected charset of the input string
247 * @param  string Target charset to convert to; defaults to RCMAIL_CHARSET
248 * @return Converted string
249 */
250function rcube_charset_convert($str, $from, $to=NULL)
251  {
252  static $mbstring_loaded = null, $convert_warning = false;
253
254  $from = strtoupper($from);
255  $to = $to==NULL ? strtoupper(RCMAIL_CHARSET) : strtoupper($to);
256  $error = false; $conv = null;
257
258  if ($from==$to || $str=='' || empty($from))
259    return $str;
260   
261  $aliases = array(
262    'UNKNOWN-8BIT'   => 'ISO-8859-15',
263    'X-UNKNOWN'      => 'ISO-8859-15',
264    'X-USER-DEFINED' => 'ISO-8859-15',
265    'ISO-8859-8-I'   => 'ISO-8859-8',
266    'KS_C_5601-1987' => 'EUC-KR',
267  );
268
269  // convert charset using iconv module 
270  if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7')
271    {
272    $aliases['GB2312'] = 'GB18030';
273    return iconv(($aliases[$from] ? $aliases[$from] : $from), ($aliases[$to] ? $aliases[$to] : $to) . "//IGNORE", $str);
274    }
275
276  // settings for mbstring module (by Tadashi Jokagi)
277  if (is_null($mbstring_loaded)) {
278    if ($mbstring_loaded = extension_loaded("mbstring"))
279      mb_internal_encoding(RCMAIL_CHARSET);
280  }
281
282  // convert charset using mbstring module
283  if ($mbstring_loaded)
284    {
285    $aliases['UTF-7'] = 'UTF7-IMAP';
286    $aliases['WINDOWS-1257'] = 'ISO-8859-13';
287   
288    // return if convert succeeded
289    if (($out = mb_convert_encoding($str, ($aliases[$to] ? $aliases[$to] : $to), ($aliases[$from] ? $aliases[$from] : $from))) != '')
290      return $out;
291    }
292   
293 
294  if (class_exists('utf8'))
295    $conv = new utf8();
296
297  // convert string to UTF-8
298  if ($from == 'UTF-7')
299    $str = utf7_to_utf8($str);
300  else if (($from == 'ISO-8859-1') && function_exists('utf8_encode'))
301    $str = utf8_encode($str);
302  else if ($from != 'UTF-8' && $conv)
303    {
304    $conv->loadCharset($from);
305    $str = $conv->strToUtf8($str);
306    }
307  else if ($from != 'UTF-8')
308    $error = true;
309
310  // encode string for output
311  if ($to == 'UTF-7')
312    return utf8_to_utf7($str);
313  else if ($to == 'ISO-8859-1' && function_exists('utf8_decode'))
314    return utf8_decode($str);
315  else if ($to != 'UTF-8' && $conv)
316    {
317    $conv->loadCharset($to);
318    return $conv->utf8ToStr($str);
319    }
320  else if ($to != 'UTF-8')
321    $error = true;
322
323  // report error
324  if ($error && !$convert_warning)
325    {
326    raise_error(array(
327      'code' => 500,
328      'type' => 'php',
329      'file' => __FILE__,
330      'message' => "Could not convert string charset. Make sure iconv is installed or lib/utf8.class is available"
331      ), true, false);
332   
333    $convert_warning = true;
334    }
335 
336  // return UTF-8 string
337  return $str;
338  }
339
340
341/**
342 * Replacing specials characters to a specific encoding type
343 *
344 * @param  string  Input string
345 * @param  string  Encoding type: text|html|xml|js|url
346 * @param  string  Replace mode for tags: show|replace|remove
347 * @param  boolean Convert newlines
348 * @return The quoted string
349 */
350function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
351  {
352  global $OUTPUT;
353  static $html_encode_arr = false;
354  static $js_rep_table = false;
355  static $xml_rep_table = false;
356
357  $charset = $OUTPUT->get_charset();
358  $is_iso_8859_1 = false;
359  if ($charset == 'ISO-8859-1') {
360    $is_iso_8859_1 = true;
361  }
362  if (!$enctype)
363    $enctype = $GLOBALS['OUTPUT_TYPE'];
364
365  // encode for plaintext
366  if ($enctype=='text')
367    return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
368
369  // encode for HTML output
370  if ($enctype=='html')
371    {
372    if (!$html_encode_arr)
373      {
374      $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);       
375      unset($html_encode_arr['?']);
376      }
377
378    $ltpos = strpos($str, '<');
379    $encode_arr = $html_encode_arr;
380
381    // don't replace quotes and html tags
382    if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false)
383      {
384      unset($encode_arr['"']);
385      unset($encode_arr['<']);
386      unset($encode_arr['>']);
387      unset($encode_arr['&']);
388      }
389    else if ($mode=='remove')
390      $str = strip_tags($str);
391   
392    // avoid douple quotation of &
393    $out = preg_replace('/&amp;([a-z]{2,5}|#[0-9]{2,4});/', '&\\1;', strtr($str, $encode_arr));
394     
395    return $newlines ? nl2br($out) : $out;
396    }
397
398  if ($enctype=='url')
399    return rawurlencode($str);
400
401  // if the replace tables for XML and JS are not yet defined
402  if ($js_rep_table===false)
403    {
404    $js_rep_table = $xml_rep_table = array();
405    $xml_rep_table['&'] = '&amp;';
406
407    for ($c=160; $c<256; $c++)  // can be increased to support more charsets
408      {
409      $xml_rep_table[Chr($c)] = "&#$c;";
410     
411      if ($is_iso_8859_1)
412        $js_rep_table[Chr($c)] = sprintf("\\u%04x", $c);
413      }
414
415    $xml_rep_table['"'] = '&quot;';
416    }
417
418  // encode for XML
419  if ($enctype=='xml')
420    return strtr($str, $xml_rep_table);
421
422  // encode for javascript use
423  if ($enctype=='js')
424    {
425    if ($charset!='UTF-8')
426      $str = rcube_charset_convert($str, RCMAIL_CHARSET,$charset);
427     
428    return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), addslashes(strtr($str, $js_rep_table)));
429    }
430
431  // no encoding given -> return original string
432  return $str;
433  }
434 
435/**
436 * Quote a given string.
437 * Shortcut function for rep_specialchars_output
438 *
439 * @return string HTML-quoted string
440 * @see rep_specialchars_output()
441 */
442function Q($str, $mode='strict', $newlines=TRUE)
443  {
444  return rep_specialchars_output($str, 'html', $mode, $newlines);
445  }
446
447/**
448 * Quote a given string for javascript output.
449 * Shortcut function for rep_specialchars_output
450 *
451 * @return string JS-quoted string
452 * @see rep_specialchars_output()
453 */
454function JQ($str)
455  {
456  return rep_specialchars_output($str, 'js');
457  }
458
459
460/**
461 * Read input value and convert it for internal use
462 * Performs stripslashes() and charset conversion if necessary
463 *
464 * @param  string   Field name to read
465 * @param  int      Source to get value from (GPC)
466 * @param  boolean  Allow HTML tags in field value
467 * @param  string   Charset to convert into
468 * @return string   Field value or NULL if not available
469 */
470function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
471  {
472  global $OUTPUT;
473  $value = NULL;
474 
475  if ($source==RCUBE_INPUT_GET && isset($_GET[$fname]))
476    $value = $_GET[$fname];
477  else if ($source==RCUBE_INPUT_POST && isset($_POST[$fname]))
478    $value = $_POST[$fname];
479  else if ($source==RCUBE_INPUT_GPC)
480    {
481    if (isset($_POST[$fname]))
482      $value = $_POST[$fname];
483    else if (isset($_GET[$fname]))
484      $value = $_GET[$fname];
485    else if (isset($_COOKIE[$fname]))
486      $value = $_COOKIE[$fname];
487    }
488 
489  // strip slashes if magic_quotes enabled
490  if ((bool)get_magic_quotes_gpc())
491    $value = stripslashes($value);
492
493  // remove HTML tags if not allowed   
494  if (!$allow_html)
495    $value = strip_tags($value);
496 
497  // convert to internal charset
498  if (is_object($OUTPUT))
499    return rcube_charset_convert($value, $OUTPUT->get_charset(), $charset);
500  else
501    return $value;
502  }
503
504/**
505 * Remove all non-ascii and non-word chars
506 * except . and -
507 */
508function asciiwords($str)
509{
510  return preg_replace('/[^a-z0-9.-_]/i', '', $str);
511}
512
513/**
514 * Remove single and double quotes from given string
515 *
516 * @param string Input value
517 * @return string Dequoted string
518 */
519function strip_quotes($str)
520{
521  return preg_replace('/[\'"]/', '', $str);
522}
523
524
525/**
526 * Remove new lines characters from given string
527 *
528 * @param string Input value
529 * @return string Stripped string
530 */
531function strip_newlines($str)
532{
533  return preg_replace('/[\r\n]/', '', $str);
534}
535
536
537/**
538 * Check if a specific template exists
539 *
540 * @param string Template name
541 * @return boolean True if template exists
542 */
543function template_exists($name)
544  {
545  global $CONFIG;
546  $skin_path = $CONFIG['skin_path'];
547
548  // check template file
549  return is_file("$skin_path/templates/$name.html");
550  }
551
552
553/**
554 * Create a HTML table based on the given data
555 *
556 * @param  array  Named table attributes
557 * @param  mixed  Table row data. Either a two-dimensional array or a valid SQL result set
558 * @param  array  List of cols to show
559 * @param  string Name of the identifier col
560 * @return string HTML table code
561 */
562function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col)
563  {
564  global $DB;
565 
566  // allow the following attributes to be added to the <table> tag
567  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
568 
569  $table = '<table' . $attrib_str . ">\n";
570   
571  // add table title
572  $table .= "<thead><tr>\n";
573
574  foreach ($a_show_cols as $col)
575    $table .= '<td class="'.$col.'">' . Q(rcube_label($col)) . "</td>\n";
576
577  $table .= "</tr></thead>\n<tbody>\n";
578 
579  $c = 0;
580  if (!is_array($table_data))
581    {
582    while ($table_data && ($sql_arr = $DB->fetch_assoc($table_data)))
583      {
584      $zebra_class = $c%2 ? 'even' : 'odd';
585
586      $table .= sprintf('<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n", $sql_arr[$id_col]);
587
588      // format each col
589      foreach ($a_show_cols as $col)
590        {
591        $cont = Q($sql_arr[$col]);
592        $table .= '<td class="'.$col.'">' . $cont . "</td>\n";
593        }
594
595      $table .= "</tr>\n";
596      $c++;
597      }
598    }
599  else
600    {
601    foreach ($table_data as $row_data)
602      {
603      $zebra_class = $c%2 ? 'even' : 'odd';
604
605      $table .= sprintf('<tr id="rcmrow%s" class="contact '.$zebra_class.'">'."\n", $row_data[$id_col]);
606
607      // format each col
608      foreach ($a_show_cols as $col)
609        {
610        $cont = Q($row_data[$col]);
611        $table .= '<td class="'.$col.'">' . $cont . "</td>\n";
612        }
613
614      $table .= "</tr>\n";
615      $c++;
616      }
617    }
618
619  // complete message table
620  $table .= "</tbody></table>\n";
621 
622  return $table;
623  }
624
625
626/**
627 * Create an edit field for inclusion on a form
628 *
629 * @param string col field name
630 * @param string value field value
631 * @param array attrib HTML element attributes for field
632 * @param string type HTML element type (default 'text')
633 * @return string HTML field definition
634 */
635function rcmail_get_edit_field($col, $value, $attrib, $type='text')
636  {
637  $fname = '_'.$col;
638  $attrib['name'] = $fname;
639 
640  if ($type=='checkbox')
641    {
642    $attrib['value'] = '1';
643    $input = new html_checkbox($attrib);
644    }
645  else if ($type=='textarea')
646    {
647    $attrib['cols'] = $attrib['size'];
648    $input = new html_textarea($attrib);
649    }
650  else
651    $input = new html_inputfield($attrib);
652
653  // use value from post
654  if (!empty($_POST[$fname]))
655    $value = get_input_value($fname, RCUBE_INPUT_POST);
656
657  $out = $input->show($value);
658         
659  return $out;
660  }
661
662
663/**
664 * Return the mail domain configured for the given host
665 *
666 * @param string IMAP host
667 * @return string Resolved SMTP host
668 */
669function rcmail_mail_domain($host)
670  {
671  global $CONFIG;
672
673  $domain = $host;
674  if (is_array($CONFIG['mail_domain']))
675    {
676    if (isset($CONFIG['mail_domain'][$host]))
677      $domain = $CONFIG['mail_domain'][$host];
678    }
679  else if (!empty($CONFIG['mail_domain']))
680    $domain = $CONFIG['mail_domain'];
681
682  return $domain;
683  }
684
685
686/**
687 * Replace all css definitions with #container [def]
688 * and remove css-inlined scripting
689 *
690 * @param string CSS source code
691 * @param string Container ID to use as prefix
692 * @return string Modified CSS source
693 */
694function rcmail_mod_css_styles($source, $container_id, $base_url = '')
695  {
696  $a_css_values = array();
697  $last_pos = 0;
698 
699  // ignore the whole block if evil styles are detected
700  if (stristr($source, 'expression') || stristr($source, 'behavior'))
701    return '';
702
703  // cut out all contents between { and }
704  while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos)))
705  {
706    $key = sizeof($a_css_values);
707    $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1));
708    $source = substr($source, 0, $pos+1) . "<<str_replacement[$key]>>" . substr($source, $pos2, strlen($source)-$pos2);
709    $last_pos = $pos+2;
710  }
711
712  // remove html comments and add #container to each tag selector.
713  // also replace body definition because we also stripped off the <body> tag
714  $styles = preg_replace(
715    array(
716      '/(^\s*<!--)|(-->\s*$)/',
717      '/(^\s*|,\s*|\}\s*)([a-z0-9\._#][a-z0-9\.\-_]*)/im',
718      '/@import\s+(url\()?[\'"]?([^\)\'"]+)[\'"]?(\))?/ime',
719      '/<<str_replacement\[([0-9]+)\]>>/e',
720      "/$container_id\s+body/i"
721    ),
722    array(
723      '',
724      "\\1#$container_id \\2",
725      "sprintf(\"@import url('./bin/modcss.php?u=%s&c=%s')\", urlencode(make_absolute_url('\\2','$base_url')), urlencode($container_id))",
726      "\$a_css_values[\\1]",
727      "$container_id div.rcmBody"
728    ),
729    $source);
730
731  return $styles;
732  }
733
734/**
735 * Try to autodetect operating system and find the correct line endings
736 *
737 * @return string The appropriate mail header delimiter
738 */
739function rcmail_header_delm()
740{
741  global $CONFIG;
742 
743  // use the configured delimiter for headers
744  if (!empty($CONFIG['mail_header_delimiter']))
745    return $CONFIG['mail_header_delimiter'];
746  else if (strtolower(substr(PHP_OS, 0, 3)=='win'))
747    return "\r\n";
748  else if (strtolower(substr(PHP_OS, 0, 3)=='mac'))
749    return "\r\n";
750  else   
751    return "\n";
752}
753
754
755/**
756 * Compose a valid attribute string for HTML tags
757 *
758 * @param array Named tag attributes
759 * @param array List of allowed attributes
760 * @return string HTML formatted attribute string
761 */
762function create_attrib_string($attrib, $allowed_attribs=array('id', 'class', 'style'))
763  {
764  // allow the following attributes to be added to the <iframe> tag
765  $attrib_str = '';
766  foreach ($allowed_attribs as $a)
767    if (isset($attrib[$a]))
768      $attrib_str .= sprintf(' %s="%s"', $a, str_replace('"', '&quot;', $attrib[$a]));
769
770  return $attrib_str;
771  }
772
773
774/**
775 * Convert a HTML attribute string attributes to an associative array (name => value)
776 *
777 * @param string Input string
778 * @return array Key-value pairs of parsed attributes
779 */
780function parse_attrib_string($str)
781  {
782  $attrib = array();
783  preg_match_all('/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]+)\2|(\S+?))/Ui', stripslashes($str), $regs, PREG_SET_ORDER);
784
785  // convert attributes to an associative array (name => value)
786  if ($regs)
787    foreach ($regs as $attr)
788      {
789      $attrib[strtolower($attr[1])] = $attr[3] . $attr[4];
790      }
791
792  return $attrib;
793  }
794
795
796/**
797 * Convert the given date to a human readable form
798 * This uses the date formatting properties from config
799 *
800 * @param mixed Date representation (string or timestamp)
801 * @param string Date format to use
802 * @return string Formatted date string
803 */
804function format_date($date, $format=NULL)
805  {
806  global $CONFIG;
807 
808  $ts = NULL;
809
810  if (is_numeric($date))
811    $ts = $date;
812  else if (!empty($date))
813    {
814    while (($ts = @strtotime($date))===false)
815      {
816        // if we have a date in non-rfc format
817        // remove token from the end and try again
818        $d = explode(' ', $date);
819        array_pop($d);
820        if (!$d) break;
821        $date = implode(' ', $d);
822      }
823    }
824
825  if (empty($ts))
826    return '';
827   
828  // get user's timezone
829  $tz = $CONFIG['timezone'];
830  if ($CONFIG['dst_active'])
831    $tz++;
832
833  // convert time to user's timezone
834  $timestamp = $ts - date('Z', $ts) + ($tz * 3600);
835 
836  // get current timestamp in user's timezone
837  $now = time();  // local time
838  $now -= (int)date('Z'); // make GMT time
839  $now += ($tz * 3600); // user's time
840  $now_date = getdate($now);
841
842  $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']);
843  $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']);
844
845  // define date format depending on current time 
846  if ($CONFIG['prettydate'] && !$format && $timestamp > $today_limit && $timestamp < $now)
847    return sprintf('%s %s', rcube_label('today'), date($CONFIG['date_today'] ? $CONFIG['date_today'] : 'H:i', $timestamp));
848  else if ($CONFIG['prettydate'] && !$format && $timestamp > $week_limit && $timestamp < $now)
849    $format = $CONFIG['date_short'] ? $CONFIG['date_short'] : 'D H:i';
850  else if (!$format)
851    $format = $CONFIG['date_long'] ? $CONFIG['date_long'] : 'd.m.Y H:i';
852
853
854  // parse format string manually in order to provide localized weekday and month names
855  // an alternative would be to convert the date() format string to fit with strftime()
856  $out = '';
857  for($i=0; $i<strlen($format); $i++)
858    {
859    if ($format{$i}=='\\')  // skip escape chars
860      continue;
861   
862    // write char "as-is"
863    if ($format{$i}==' ' || $format{$i-1}=='\\')
864      $out .= $format{$i};
865    // weekday (short)
866    else if ($format{$i}=='D')
867      $out .= rcube_label(strtolower(date('D', $timestamp)));
868    // weekday long
869    else if ($format{$i}=='l')
870      $out .= rcube_label(strtolower(date('l', $timestamp)));
871    // month name (short)
872    else if ($format{$i}=='M')
873      $out .= rcube_label(strtolower(date('M', $timestamp)));
874    // month name (long)
875    else if ($format{$i}=='F')
876      $out .= rcube_label('long'.strtolower(date('M', $timestamp)));
877    else
878      $out .= date($format{$i}, $timestamp);
879    }
880 
881  return $out;
882  }
883
884
885/**
886 * Compose a valid representaion of name and e-mail address
887 *
888 * @param string E-mail address
889 * @param string Person name
890 * @return string Formatted string
891 */
892function format_email_recipient($email, $name='')
893  {
894  if ($name && $name != $email)
895    {
896    // Special chars as defined by RFC 822 need to in quoted string (or escaped).
897    return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, $email);
898    }
899  else
900    return $email;
901  }
902
903
904
905/****** debugging functions ********/
906
907
908/**
909 * Print or write debug messages
910 *
911 * @param mixed Debug message or data
912 */
913function console($msg)
914  {
915  if (!is_string($msg))
916    $msg = var_export($msg, true);
917
918  if (!($GLOBALS['CONFIG']['debug_level'] & 4))
919    write_log('console', $msg);
920  else if ($GLOBALS['OUTPUT']->ajax_call)
921    print "/*\n $msg \n*/\n";
922  else
923    {
924    print '<div style="background:#eee; border:1px solid #ccc; margin-bottom:3px; padding:6px"><pre>';
925    print $msg;
926    print "</pre></div>\n";
927    }
928  }
929
930
931/**
932 * Append a line to a logfile in the logs directory.
933 * Date will be added automatically to the line.
934 *
935 * @param $name name of log file
936 * @param line Line to append
937 */
938function write_log($name, $line)
939  {
940  global $CONFIG;
941
942  if (!is_string($line))
943    $line = var_export($line, true);
944 
945  $log_entry = sprintf("[%s]: %s\n",
946                 date("d-M-Y H:i:s O", mktime()),
947                 $line);
948                 
949  if (empty($CONFIG['log_dir']))
950    $CONFIG['log_dir'] = INSTALL_PATH.'logs';
951     
952  // try to open specific log file for writing
953  if ($fp = @fopen($CONFIG['log_dir'].'/'.$name, 'a'))   
954    {
955    fwrite($fp, $log_entry);
956    fclose($fp);
957    }
958  }
959
960
961/**
962 * @access private
963 */
964function rcube_timer()
965  {
966  list($usec, $sec) = explode(" ", microtime());
967  return ((float)$usec + (float)$sec);
968  }
969 
970
971/**
972 * @access private
973 */
974function rcube_print_time($timer, $label='Timer')
975  {
976  static $print_count = 0;
977 
978  $print_count++;
979  $now = rcube_timer();
980  $diff = $now-$timer;
981 
982  if (empty($label))
983    $label = 'Timer '.$print_count;
984 
985  console(sprintf("%s: %0.4f sec", $label, $diff));
986  }
987
988
989/**
990 * Return the mailboxlist in HTML
991 *
992 * @param array Named parameters
993 * @return string HTML code for the gui object
994 */
995function rcmail_mailbox_list($attrib)
996  {
997  global $IMAP, $CONFIG, $OUTPUT, $COMM_PATH;
998  static $s_added_script = FALSE;
999  static $a_mailboxes;
1000
1001  // add some labels to client
1002  rcube_add_label('purgefolderconfirm');
1003  rcube_add_label('deletemessagesconfirm');
1004 
1005// $mboxlist_start = rcube_timer();
1006 
1007  $type = $attrib['type'] ? $attrib['type'] : 'ul';
1008  $add_attrib = $type=='select' ? array('style', 'class', 'id', 'name', 'onchange') :
1009                                  array('style', 'class', 'id');
1010                                 
1011  if ($type=='ul' && !$attrib['id'])
1012    $attrib['id'] = 'rcmboxlist';
1013
1014  // allow the following attributes to be added to the <ul> tag
1015  $attrib_str = create_attrib_string($attrib, $add_attrib);
1016 
1017  $out = '<' . $type . $attrib_str . ">\n";
1018 
1019  // add no-selection option
1020  if ($type=='select' && $attrib['noselection'])
1021    $out .= sprintf('<option value="0">%s</option>'."\n",
1022                    rcube_label($attrib['noselection']));
1023 
1024  // get mailbox list
1025  $mbox_name = $IMAP->get_mailbox_name();
1026 
1027  // build the folders tree
1028  if (empty($a_mailboxes))
1029    {
1030    // get mailbox list
1031    $a_folders = $IMAP->list_mailboxes();
1032    $delimiter = $IMAP->get_hierarchy_delimiter();
1033    $a_mailboxes = array();
1034
1035// rcube_print_time($mboxlist_start, 'list_mailboxes()');
1036
1037    foreach ($a_folders as $folder)
1038      rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter);
1039    }
1040
1041// var_dump($a_mailboxes);
1042
1043  if ($type=='select')
1044    $out .= rcmail_render_folder_tree_select($a_mailboxes, $mbox_name, $attrib['maxlength']);
1045   else
1046    $out .= rcmail_render_folder_tree_html($a_mailboxes, $mbox_name, $attrib['maxlength']);
1047
1048// rcube_print_time($mboxlist_start, 'render_folder_tree()');
1049
1050
1051  if ($type=='ul')
1052    $OUTPUT->add_gui_object('mailboxlist', $attrib['id']);
1053
1054  return $out . "</$type>";
1055  }
1056
1057
1058
1059
1060/**
1061 * Create a hierarchical array of the mailbox list
1062 * @access private
1063 */
1064function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='')
1065  {
1066  $pos = strpos($folder, $delm);
1067  if ($pos !== false)
1068    {
1069    $subFolders = substr($folder, $pos+1);
1070    $currentFolder = substr($folder, 0, $pos);
1071    }
1072  else
1073    {
1074    $subFolders = false;
1075    $currentFolder = $folder;
1076    }
1077
1078  $path .= $currentFolder;
1079
1080  if (!isset($arrFolders[$currentFolder]))
1081    {
1082    $arrFolders[$currentFolder] = array('id' => $path,
1083                                        'name' => rcube_charset_convert($currentFolder, 'UTF-7'),
1084                                        'folders' => array());
1085    }
1086
1087  if (!empty($subFolders))
1088    rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm);
1089  }
1090 
1091
1092/**
1093 * Return html for a structured list &lt;ul&gt; for the mailbox tree
1094 * @access private
1095 */
1096function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, $maxlength, $nestLevel=0)
1097  {
1098  global $COMM_PATH, $IMAP, $CONFIG, $OUTPUT;
1099
1100  $idx = 0;
1101  $out = '';
1102  foreach ($arrFolders as $key => $folder)
1103    {
1104    $zebra_class = ($nestLevel*$idx)%2 ? 'even' : 'odd';
1105    $title = '';
1106
1107    if ($folder_class = rcmail_folder_classname($folder['id']))
1108      $foldername = rcube_label($folder_class);
1109    else
1110      {
1111      $foldername = $folder['name'];
1112
1113      // shorten the folder name to a given length
1114      if ($maxlength && $maxlength>1)
1115        {
1116        $fname = abbreviate_string($foldername, $maxlength);
1117        if ($fname != $foldername)
1118          $title = ' title="'.Q($foldername).'"';
1119        $foldername = $fname;
1120        }
1121      }
1122
1123    // make folder name safe for ids and class names
1124    $folder_id = preg_replace('/[^A-Za-z0-9\-_]/', '', $folder['id']);
1125    $class_name = preg_replace('/[^a-z0-9\-_]/', '', $folder_class ? $folder_class : strtolower($folder['id']));
1126
1127    // set special class for Sent, Drafts, Trash and Junk
1128    if ($folder['id']==$CONFIG['sent_mbox'])
1129      $class_name = 'sent';
1130    else if ($folder['id']==$CONFIG['drafts_mbox'])
1131      $class_name = 'drafts';
1132    else if ($folder['id']==$CONFIG['trash_mbox'])
1133      $class_name = 'trash';
1134    else if ($folder['id']==$CONFIG['junk_mbox'])
1135      $class_name = 'junk';
1136
1137    $js_name = htmlspecialchars(JQ($folder['id']));
1138    $out .= sprintf('<li id="rcmli%s" class="mailbox %s %s%s%s"><a href="%s"'.
1139                    ' onclick="return %s.command(\'list\',\'%s\',this)"'.
1140                    ' onmouseover="return %s.focus_folder(\'%s\')"' .
1141                    ' onmouseout="return %s.unfocus_folder(\'%s\')"' .
1142                    ' onmouseup="return %s.folder_mouse_up(\'%s\')"%s>%s</a>',
1143                    $folder_id,
1144                    $class_name,
1145                    $zebra_class,
1146                    $unread_count ? ' unread' : '',
1147                    $folder['id']==$mbox_name ? ' selected' : '',
1148                    Q(rcmail_url('', array('_mbox' => $folder['id']))),
1149                    JS_OBJECT_NAME,
1150                    $js_name,
1151                    JS_OBJECT_NAME,
1152                    $js_name,
1153                    JS_OBJECT_NAME,
1154                    $js_name,
1155                    JS_OBJECT_NAME,
1156                    $js_name,
1157                    $title,
1158                    Q($foldername));
1159
1160    if (!empty($folder['folders']))
1161      $out .= "\n<ul>\n" . rcmail_render_folder_tree_html($folder['folders'], $mbox_name, $maxlength, $nestLevel+1) . "</ul>\n";
1162
1163    $out .= "</li>\n";
1164    $idx++;
1165    }
1166
1167  return $out;
1168  }
1169
1170
1171/**
1172 * Return html for a flat list <select> for the mailbox tree
1173 * @access private
1174 */
1175function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, $nestLevel=0, $selected='')
1176  {
1177  global $IMAP, $OUTPUT;
1178
1179  $idx = 0;
1180  $out = '';
1181  foreach ($arrFolders as $key=>$folder)
1182    {
1183    if ($folder_class = rcmail_folder_classname($folder['id']))
1184      $foldername = rcube_label($folder_class);
1185    else
1186      {
1187      $foldername = $folder['name'];
1188     
1189      // shorten the folder name to a given length
1190      if ($maxlength && $maxlength>1)
1191        $foldername = abbreviate_string($foldername, $maxlength);
1192      }
1193
1194    $out .= sprintf('<option value="%s"%s>%s%s</option>'."\n",
1195                    htmlspecialchars($folder['id']),
1196                    ($selected == $foldername ? ' selected="selected"' : ''),
1197                    str_repeat('&nbsp;', $nestLevel*4),
1198                    Q($foldername));
1199
1200    if (!empty($folder['folders']))
1201      $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, $nestLevel+1, $selected);
1202
1203    $idx++;
1204    }
1205
1206  return $out;
1207  }
1208
1209
1210/**
1211 * Return internal name for the given folder if it matches the configured special folders
1212 * @access private
1213 */
1214function rcmail_folder_classname($folder_id)
1215{
1216  global $CONFIG;
1217
1218  $cname = null;
1219  $folder_lc = strtolower($folder_id);
1220 
1221  // for these mailboxes we have localized labels and css classes
1222  foreach (array('inbox', 'sent', 'drafts', 'trash', 'junk') as $smbx)
1223  {
1224    if ($folder_lc == $smbx || $folder_id == $CONFIG[$smbx.'_mbox'])
1225      $cname = $smbx;
1226  }
1227 
1228  return $cname;
1229}
1230
1231
1232/**
1233 * Try to localize the given IMAP folder name.
1234 * UTF-7 decode it in case no localized text was found
1235 *
1236 * @param string Folder name
1237 * @return string Localized folder name in UTF-8 encoding
1238 */
1239function rcmail_localize_foldername($name)
1240{
1241  if ($folder_class = rcmail_folder_classname($name))
1242    return rcube_label($folder_class);
1243  else
1244    return rcube_charset_convert($name, 'UTF-7');
1245}
1246
1247
1248?>
Note: See TracBrowser for help on using the repository browser.