summaryrefslogtreecommitdiff
path: root/program/include/rcube_shared.inc
diff options
context:
space:
mode:
Diffstat (limited to 'program/include/rcube_shared.inc')
-rw-r--r--program/include/rcube_shared.inc1417
1 files changed, 1417 insertions, 0 deletions
diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc
new file mode 100644
index 000000000..2c0b0517b
--- /dev/null
+++ b/program/include/rcube_shared.inc
@@ -0,0 +1,1417 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | rcube_shared.inc |
+ | |
+ | This file is part of the RoundCube PHP suite |
+ | Copyright (C) 2005, RoundCube Dev. - Switzerland |
+ | All rights reserved. |
+ | |
+ | CONTENTS: |
+ | Shared functions and classes used in PHP projects |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+
+// ********* round cube schared classes *********
+
+class rcube_html_page
+ {
+ var $css;
+
+ var $scripts_path = '';
+ var $script_files = array();
+ var $scripts = array();
+
+ var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
+ var $script_tag = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
+
+ var $title = '';
+ var $header = '';
+ var $footer = '';
+ var $body = '';
+ var $body_attrib = array();
+ var $meta_tags = array();
+
+
+ // PHP 5 constructor
+ function __construct()
+ {
+ $this->css = new rcube_css();
+ }
+
+ // PHP 4 compatibility
+ function rcube_html_page()
+ {
+ $this->__construct();
+ }
+
+
+ function include_script($file, $position='head')
+ {
+ static $sa_files = array();
+
+ if (in_array($file, $sa_files))
+ return;
+
+ if (!is_array($this->script_files[$position]))
+ $this->script_files[$position] = array();
+
+ $this->script_files[$position][] = $file;
+ }
+
+
+ function add_script($script, $position='head')
+ {
+ if (!isset($this->scripts[$position]))
+ $this->scripts[$position] = '';
+
+ $this->scripts[$position] .= "\n$script";
+ }
+
+
+ function set_title()
+ {
+
+ }
+
+
+ function write($templ='', $base_path='')
+ {
+ $output = trim($templ);
+
+ // set default page title
+ if (!strlen($this->title))
+ $this->title = 'RoundCube|Mail';
+
+ // replace specialchars in content
+ $__page_title = rep_specialchars_output($this->title, 'html', 'show', FALSE);
+ $__page_header = $__page_body = $__page_footer = '';
+
+
+ // definition of the code to be placed in the document header and footer
+ if (is_array($this->script_files['head']))
+ foreach ($this->script_files['head'] as $file)
+ $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file);
+
+ if (strlen($this->scripts['head']))
+ $__page_header .= sprintf($this->script_tag, $this->scripts['head']);
+
+ if (is_array($this->script_files['foot']))
+ foreach ($this->script_files['foot'] as $file)
+ $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file);
+
+ if (strlen($this->scripts['foot']))
+ $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']);
+
+
+ $__page_header .= $this->css->show();
+
+
+ // find page header
+ if($hpos = strpos(strtolower($output), '</head>'))
+ $__page_header .= "\n";
+ else
+ {
+ if (!is_numeric($hpos))
+ $hpos = strpos(strtolower($output), '<body');
+ if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html')))
+ {
+ while($output[$hpos]!='>')
+ $hpos++;
+ $hpos++;
+ }
+
+ $__page_header = "<head>\n<title>$__page_title</title>\n$__page_header\n</head>\n";
+ }
+
+ // add page hader
+ if($hpos)
+ $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output));
+ else
+ $output = $__page_header . $output;
+
+
+ // find page body
+ if($bpos = strpos(strtolower($output), '<body'))
+ {
+ while($output[$bpos]!='>') $bpos++;
+ $bpos++;
+ }
+ else
+ $bpos = strpos(strtolower($output), '</head>')+7;
+
+ // add page body
+ if($bpos && $__page_body)
+ $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output));
+
+
+ // find and add page footer
+ if(($fpos = strpos(strtolower($output), '</body>')) || ($fpos = strpos(strtolower($output), '</html>')))
+ $output = substr($output,0,$fpos) . "$__page_footer\n" . substr($output,$fpos,strlen($output));
+ else
+ $output .= "\n$__page_footer";
+
+
+ // reset those global vars
+ $__page_header = $__page_footer = '';
+
+
+ // correct absolute pathes in images and other tags
+ $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output);
+
+ print $output;
+ }
+
+
+ function _parse($templ)
+ {
+
+ }
+ }
+
+
+
+
+class rcube_css
+ {
+ var $css_data = array();
+
+ var $css_groups = array();
+
+ var $include_files = array();
+
+ var $grouped_output = TRUE;
+
+ var $content_type = 'text/css';
+
+ var $base_path = '';
+
+ var $indent_chars = "\t";
+
+
+ // add or overwrite a css definition
+ // either pass porperty and value as separate arguments
+ // or provide an associative array as second argument
+ function set_style($selector, $property, $value='')
+ {
+ $a_elements = $this->_parse_selectors($selector);
+ foreach ($a_elements as $element)
+ {
+ if (!is_array($property))
+ $property = array($property => $value);
+
+ foreach ($property as $name => $value)
+ $this->css_data[$element][strtolower($name)] = $value;
+ }
+
+ // clear goups array
+ $this->css_groups = array();
+ }
+
+
+ // unset a style property
+ function remove_style($selector, $property)
+ {
+ if (!is_array($property))
+ $property = array($property);
+
+ foreach ($property as $key)
+ unset($this->css_data[$selector][strtolower($key)]);
+
+ // clear goups array
+ $this->css_groups = array();
+ }
+
+
+ // define base path for external css files
+ function set_basepath($path)
+ {
+ $this->base_path = preg_replace('/\/$/', '', $path);
+ }
+
+
+ // enable/disable grouped output
+ function set_grouped_output($grouped)
+ {
+ $this->grouped_output = $grouped;
+ }
+
+
+ // add a css file as external source
+ function include_file($filename, $media='')
+ {
+ // include multiple files
+ if (is_array($filename))
+ {
+ foreach ($filename as $file)
+ $this->include_file($file, $media);
+ }
+ // add single file
+ else if (!in_array($filename, $this->include_files))
+ $this->include_files[] = array('file' => $filename,
+ 'media' => $media);
+ }
+
+
+ // parse css code
+ function import_string($str)
+ {
+ $ret = FALSE;
+ if (strlen($str))
+ $ret = $this->_parse($str);
+
+ return $ret;
+ }
+
+
+ // open and parse a css file
+ function import_file($file)
+ {
+ $ret = FALSE;
+
+ if (!is_file($file))
+ return $ret;
+
+ // for php version >= 4.3.0
+ if (function_exists('file_get_contents'))
+ $ret = $this->_parse(file_get_contents($file));
+
+ // for order php versions
+ else if ($fp = fopen($file, 'r'))
+ {
+ $ret = $this->_parse(fread($fp, filesize($file)));
+ fclose($fp);
+ }
+
+ return $ret;
+ }
+
+
+ // copy all properties inherited from superior styles to a specific selector
+ function copy_inherited_styles($selector)
+ {
+ // get inherited props from body and tag/class selectors
+ $css_props = $this->_get_inherited_styles($selector);
+
+ // write modified props back and clear goups array
+ if (sizeof($css_props))
+ {
+ $this->css_data[$selector] = $css_props;
+ $this->css_groups = array();
+ }
+ }
+
+
+ // return css definition for embedding in HTML
+ function show()
+ {
+ $out = '';
+
+ // include external css files
+ if (sizeof($this->include_files))
+ foreach ($this->include_files as $file_arr)
+ $out .= sprintf('<link rel="stylesheet" type="%s" href="%s"%s>'."\n",
+ $this->content_type,
+ $this->_get_file_path($file_arr['file']),
+ $file_arr['media'] ? ' media="'.$file_arr['media'].'"' : '');
+
+
+ // compose css string
+ if (sizeof($this->css_data))
+ $out .= sprintf("<style type=\"%s\">\n<!--\n\n%s-->\n</style>",
+ $this->content_type,
+ $this->to_string());
+
+
+ return $out;
+ }
+
+
+ // return valid css code of the current styles grid
+ function to_string($selector=NULL)
+ {
+ // return code for a single selector
+ if ($selector)
+ {
+ $indent_str = $this->indent_chars;
+ $this->indent_chars = '';
+
+ $prop_arr = $this->to_array($selector);
+ $out = $this->_style2string($prop_arr, TRUE);
+
+ $this->indent_chars = $indent_str;
+ }
+
+ // compose css code for complete data grid
+ else
+ {
+ $out = '';
+ $css_data = $this->to_array();
+
+ foreach ($css_data as $key => $prop_arr)
+ $out .= sprintf("%s {\n%s}\n\n",
+ $key,
+ $this->_style2string($prop_arr, TRUE));
+ }
+
+ return $out;
+ }
+
+
+ // return a single-line string of a css definition
+ function to_inline($selector)
+ {
+ if ($this->css_data[$selector])
+ return str_replace('"', '\\"', $this->_style2string($this->css_data[$selector], FALSE));
+ }
+
+
+ // return an associative array with selector(s) as key and styles array as value
+ function to_array($selector=NULL)
+ {
+ if (!$selector && $this->grouped_output)
+ {
+ // build groups if desired
+ if (!sizeof($this->css_groups))
+ $this->_build_groups();
+
+ // modify group array to get an array(selector => properties)
+ $out_arr = array();
+ foreach ($this->css_groups as $group_arr)
+ {
+ $key = join(', ', $group_arr['selectors']);
+ $out_arr[$key] = $group_arr['properties'];
+ }
+ }
+ else
+ $out_arr = $this->css_data;
+
+ return $selector ? $out_arr[$selector] : $out_arr;
+ }
+
+
+ // create a css file
+ function to_file($filepath)
+ {
+ if ($fp = fopen($filepath, 'w'))
+ {
+ fwrite($fp, $this->to_string());
+ fclose($fp);
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+
+ // alias method for import_string() [DEPRECATED]
+ function add($str)
+ {
+ $this->import_string($str);
+ }
+
+ // alias method for to_string() [DEPRECATED]
+ function get()
+ {
+ return $this->to_string();
+ }
+
+
+
+ // ******** private methods ********
+
+
+ // parse a string and add styles to internal data grid
+ function _parse($str)
+ {
+ // remove comments
+ $str = preg_replace("/\/\*(.*)?\*\//Usi", '', $str);
+
+ // parse style definitions
+ if (!preg_match_all ('/([a-z0-9\.#*:_][a-z0-9\.\-_#:*,\[\]\(\)\s\"\'\+\|>~=]+)\s*\{([^\}]*)\}/ims', $str, $matches, PREG_SET_ORDER))
+ return FALSE;
+
+
+ foreach ($matches as $match_arr)
+ {
+ // split selectors into array
+ $a_keys = $this->_parse_selectors(trim($match_arr[1]));
+
+ // parse each property of an element
+ $codes = explode(";", trim($match_arr[2]));
+ foreach ($codes as $code)
+ {
+ if (strlen(trim($code))>0)
+ {
+ // find the property and the value
+ if (!($sep = strpos($code, ':')))
+ continue;
+
+ $property = strtolower(trim(substr($code, 0, $sep)));
+ $value = trim(substr($code, $sep+1));
+
+ // add the property to the object array
+ foreach ($a_keys as $key)
+ $this->css_data[$key][$property] = $value;
+ }
+ }
+ }
+
+ // clear goups array
+ if (sizeof($matches))
+ {
+ $this->css_groups = array();
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+
+ // split selector group
+ function _parse_selectors($selector)
+ {
+ // trim selector and remove multiple spaces
+ $selector = preg_replace('/\s+/', ' ', trim($selector));
+
+ if (strpos($selector, ','))
+ return preg_split('/[\t\s\n\r]*,[\t\s\n\r]*/mi', $selector);
+ else
+ return array($selector);
+ }
+
+
+ // compare identical styles and make groups
+ function _build_groups()
+ {
+ // clear group array
+ $this->css_groups = array();
+ $string_group_map = array();
+
+ // bulild css string for each selector and check if the same is already defines
+ foreach ($this->css_data as $selector => $prop_arr)
+ {
+ // make shure to compare props in the same order
+ ksort($prop_arr);
+ $compare_str = preg_replace('/[\s\t]+/', '', $this->_style2string($prop_arr, FALSE));
+
+ // add selector to extisting group
+ if (isset($string_group_map[$compare_str]))
+ {
+ $group_index = $string_group_map[$compare_str];
+ $this->css_groups[$group_index]['selectors'][] = $selector;
+ }
+
+ // create new group
+ else
+ {
+ $i = sizeof($this->css_groups);
+ $string_group_map[$compare_str] = $i;
+ $this->css_groups[$i] = array('selectors' => array($selector),
+ 'properties' => $this->css_data[$selector]);
+ }
+ }
+ }
+
+
+ // convert the prop array into a valid css definition
+ function _style2string($prop_arr, $multiline=TRUE)
+ {
+ $out = '';
+ $delm = $multiline ? "\n" : '';
+ $spacer = $multiline ? ' ' : '';
+ $indent = $multiline ? $this->indent_chars : '';
+
+ if (is_array($prop_arr))
+ foreach ($prop_arr as $prop => $value)
+ if (strlen($value))
+ $out .= sprintf('%s%s:%s%s;%s',
+ $indent,
+ $prop,
+ $spacer,
+ $value,
+ $delm);
+
+ return $out;
+ }
+
+
+ // copy all properties inherited from superior styles to a specific selector
+ function _get_inherited_styles($selector, $loop=FALSE)
+ {
+ $css_props = $this->css_data[$selector] ? $this->css_data[$selector] : array();
+
+ // get styles from tag selector
+ if (preg_match('/(([a-z0-9]*)(\.[^\s]+)?)$/i', $selector, $regs))
+ {
+ $sel = $regs[1];
+ $tagname = $regs[2];
+ $class = $regs[3];
+
+ if ($sel && is_array($this->css_data[$sel]))
+ $css_props = $this->_merge_styles($this->css_data[$sel], $css_props);
+
+ if ($class && is_array($this->css_data[$class]))
+ $css_props = $this->_merge_styles($this->css_data[$class], $css_props);
+
+ if ($tagname && is_array($this->css_data[$tagname]))
+ $css_props = $this->_merge_styles($this->css_data[$tagname], $css_props);
+ }
+
+ // analyse inheritance
+ if (strpos($selector, ' '))
+ {
+ $a_hier = split(' ', $selector);
+ if (sizeof($a_hier)>1)
+ {
+ array_pop($a_hier);
+ $base_selector = join(' ', $a_hier);
+
+ // call this method recursively
+ $new_props = $this->_get_inherited_styles($base_selector, TRUE);
+ $css_props = $this->_merge_styles($new_props, $css_props);
+ }
+ }
+
+ // get body style
+ if (!$loop && is_array($this->css_data['body']))
+ $css_props = $this->_merge_styles($this->css_data['body'], $css_props);
+
+ return $css_props;
+ }
+
+
+ // merge two arrays with style properties together like a browser would do
+ function _merge_styles($one, $two)
+ {
+ // these properties are additive
+ foreach (array('text-decoration') as $prop)
+ if ($one[$prop] && $two[$prop])
+ {
+ // if value contains 'none' it's ignored
+ if (strstr($one[$prop], 'none'))
+ continue;
+ else if (strstr($two[$prop], 'none'))
+ unset($two[$prop]);
+
+ $a_values_one = split(' ', $one[$prop]);
+ $a_values_two = split(' ', $two[$prop]);
+ $two[$prop] = join(' ', array_unique(array_merge($a_values_one, $a_values_two)));
+ }
+
+ return array_merge($one, $two);
+ }
+
+
+ // resolve file path
+ function _get_file_path($file)
+ {
+ if (!$this->base_path && $GLOBALS['CSS_PATH'])
+ $this->set_basepath($GLOBALS['CSS_PATH']);
+
+ $base = ($file{0}=='/' || $file{0}=='.' || substr($file, 0, 7)=='http://') ? '' :
+ ($this->base_path ? $this->base_path.'/' : '');
+ return $base.$file;
+ }
+
+ }
+
+
+
+class base_form_element
+ {
+ var $uppertags = FALSE;
+ var $upperattribs = FALSE;
+ var $upperprops = FALSE;
+ var $newline = FALSE;
+
+ var $attrib = array();
+
+
+ // create string with attributes
+ function create_attrib_string($tagname='')
+ {
+ if (!sizeof($this->attrib))
+ return '';
+
+ if ($this->name!='')
+ $this->attrib['name'] = $this->name;
+
+ $attrib_arr = array();
+ foreach ($this->attrib as $key => $value)
+ {
+ // don't output some internally used attributes
+ if (in_array($key, array('form', 'quicksearch')))
+ continue;
+
+ // skip if size if not numeric
+ if (($key=='size' && !is_numeric($value)))
+ continue;
+
+ // skip empty eventhandlers
+ if ((strpos($key,'on')===0 && $value==''))
+ continue;
+
+ // encode textarea content
+ if ($key=='value')
+ $value = rep_specialchars_output($value, 'html', 'replace', FALSE);
+
+ // attributes with no value
+ if (in_array($key, array('checked', 'multiple', 'disabled', 'selected')))
+ {
+ if ($value)
+ $attrib_arr[] = $key;
+ }
+ // don't convert size of value attribute
+ else if ($key=='value')
+ $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $value, 'value');
+
+ // regular tag attributes
+ else
+ $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case($value, 'value'));
+ }
+
+ return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
+ }
+
+
+ // convert tags and attributes to upper-/lowercase
+ // $type can either be "tag" or "attrib"
+ function _conv_case($str, $type='attrib')
+ {
+ if ($type == 'tag')
+ return $this->uppertags ? strtoupper($str) : strtolower($str);
+ else if ($type == 'attrib')
+ return $this->upperattribs ? strtoupper($str) : strtolower($str);
+ else if ($type == 'value')
+ return $this->upperprops ? strtoupper($str) : strtolower($str);
+ }
+ }
+
+
+class input_field extends base_form_element
+ {
+ var $type = 'text';
+
+ // PHP 5 constructor
+ function __construct($attrib=NULL)
+ {
+ if (is_array($attrib))
+ $this->attrib = $attrib;
+
+ if ($attrib['type'])
+ $this->type = $attrib['type'];
+
+ if ($attrib['newline'])
+ $this->newline = TRUE;
+ }
+
+ // PHP 4 compatibility
+ function input_field($attrib=array())
+ {
+ $this->__construct($attrib);
+ }
+
+ // compose input tag
+ function show($value=NULL, $attrib=NULL)
+ {
+ // overwrite object attributes
+ if (is_array($attrib))
+ $this->attrib = array_merge($this->attrib, $attrib);
+
+ // set value attribute
+ if ($value!==NULL)
+ $this->attrib['value'] = $value;
+
+ $this->attrib['type'] = $this->type;
+
+ // return final tag
+ return sprintf('<%s%s />%s',
+ $this->_conv_case('input', 'tag'),
+ $this->create_attrib_string(),
+ ($this->newline ? "\n" : ""));
+ }
+ }
+
+
+class textfield extends input_field
+ {
+ var $type = 'text';
+ }
+
+class passwordfield extends input_field
+ {
+ var $type = 'password';
+ }
+
+class radiobutton extends input_field
+ {
+ var $type = 'radio';
+ }
+
+class checkbox extends input_field
+ {
+ var $type = 'checkbox';
+
+
+ function show($value='', $attrib=NULL)
+ {
+ // overwrite object attributes
+ if (is_array($attrib))
+ $this->attrib = array_merge($this->attrib, $attrib);
+
+ $this->attrib['type'] = $this->type;
+
+ if ($value && (string)$value==(string)$this->attrib['value'])
+ $this->attrib['checked'] = TRUE;
+ else
+ $this->attrib['checked'] = FALSE;
+
+ // return final tag
+ return sprintf('<%s%s />%s',
+ $this->_conv_case('input', 'tag'),
+ $this->create_attrib_string(),
+ ($this->newline ? "\n" : ""));
+ }
+ }
+
+
+class textarea extends base_form_element
+ {
+ // PHP 5 constructor
+ function __construct($attrib=array())
+ {
+ $this->attrib = $attrib;
+
+ if ($attrib['newline'])
+ $this->newline = TRUE;
+ }
+
+ // PHP 4 compatibility
+ function textarea($attrib=array())
+ {
+ $this->__construct($attrib);
+ }
+
+ function show($value='', $attrib=NULL)
+ {
+ // overwrite object attributes
+ if (is_array($attrib))
+ $this->attrib = array_merge($this->attrib, $attrib);
+
+ // take value attribute as content
+ if ($value=='')
+ $value = $this->attrib['value'];
+
+ // make shure we don't print the value attribute
+ if (isset($this->attrib['value']))
+ unset($this->attrib['value']);
+
+ if (strlen($value))
+ $value = rep_specialchars_output($value, 'html', 'replace', FALSE);
+
+ // return final tag
+ return sprintf('<%s%s>%s</%s>%s',
+ $this->_conv_case('textarea', 'tag'),
+ $this->create_attrib_string(),
+ $value,
+ $this->_conv_case('textarea', 'tag'),
+ ($this->newline ? "\n" : ""));
+ }
+ }
+
+
+class hiddenfield extends base_form_element
+ {
+ var $fields_arr = array();
+ var $newline = TRUE;
+
+ // PHP 5 constructor
+ function __construct($attrib=NULL)
+ {
+ if (is_array($attrib))
+ $this->add($attrib);
+ }
+
+ // PHP 4 compatibility
+ function hiddenfield($attrib=NULL)
+ {
+ $this->__construct($attrib);
+ }
+
+ // add a hidden field to this instance
+ function add($attrib)
+ {
+ $this->fields_arr[] = $attrib;
+ }
+
+
+ function show()
+ {
+ $out = '';
+ foreach ($this->fields_arr as $attrib)
+ {
+ $this->attrib = $attrib;
+ $this->attrib['type'] = 'hidden';
+
+ $out .= sprintf('<%s%s />%s',
+ $this->_conv_case('input', 'tag'),
+ $this->create_attrib_string(),
+ ($this->newline ? "\n" : ""));
+ }
+
+ return $out;
+ }
+ }
+
+
+class select extends base_form_element
+ {
+ var $options = array();
+
+ /*
+ syntax:
+ -------
+ // create instance. arguments are used to set attributes of select-tag
+ $select = new select(array('name' => 'fieldname'));
+
+ // add one option
+ $select->add('Switzerland', 'CH');
+
+ // add multiple options
+ $select->add(array('Switzerland', 'Germany'),
+ array('CH', 'DE'));
+
+ // add 10 blank options with 50 chars
+ // used to fill with javascript (necessary for 4.x browsers)
+ $select->add_blank(10, 50);
+
+ // generate pulldown with selection 'Switzerland' and return html-code
+ // as second argument the same attributes available to instanciate can be used
+ print $select->show('CH');
+ */
+
+ // PHP 5 constructor
+ function __construct($attrib=NULL)
+ {
+ if (is_array($attrib))
+ $this->attrib = $attrib;
+
+ if ($attrib['newline'])
+ $this->newline = TRUE;
+ }
+
+ // PHP 4 compatibility
+ function select($attrib=NULL)
+ {
+ $this->__construct($attrib);
+ }
+
+
+ function add($names, $values=NULL)
+ {
+ if (is_array($names))
+ {
+ foreach ($names as $i => $text)
+ $this->options[] = array('text' => $text, 'value' => (string)$values[$i]);
+ }
+ else
+ {
+ $this->options[] = array('text' => $names, 'value' => (string)$values);
+ }
+ }
+
+
+ function add_blank($nr, $width=0)
+ {
+ $text = $width ? str_repeat('&nbsp;', $width) : '';
+
+ for ($i=0; $i < $nr; $i++)
+ $this->options[] = array('text' => $text);
+ }
+
+
+ function show($select=array(), $attrib=NULL)
+ {
+ $options_str = "\n";
+ $value_str = $this->_conv_case(' value="%s"', 'attrib');
+
+ if (!is_array($select))
+ $select = array((string)$select);
+
+ foreach ($this->options as $option)
+ {
+ $selected = ((strlen($option['value']) && in_array($option['value'], $select, TRUE)) ||
+ (in_array($option['text'], $select, TRUE))) ? $this->_conv_case(' selected', 'attrib') : '';
+
+ $options_str .= sprintf("<%s%s%s>%s</%s>\n",
+ $this->_conv_case('option', 'tag'),
+ strlen($option['value']) ? sprintf($value_str, $option['value']) : '',
+ $selected,
+ rep_specialchars_output($option['text'], 'html', 'replace', FALSE),
+ $this->_conv_case('option', 'tag'));
+ }
+
+ // return final tag
+ return sprintf('<%s%s>%s</%s>%s',
+ $this->_conv_case('select', 'tag'),
+ $this->create_attrib_string(),
+ $options_str,
+ $this->_conv_case('select', 'tag'),
+ ($this->newline ? "\n" : ""));
+ }
+ }
+
+
+
+
+// ********* rcube schared functions *********
+
+
+// provide details about the client's browser
+function rcube_browser()
+ {
+ global $HTTP_USER_AGENT;
+
+ $bw['ver'] = 0;
+ $bw['win'] = stristr($HTTP_USER_AGENT, 'win');
+ $bw['mac'] = stristr($HTTP_USER_AGENT, 'mac');
+ $bw['linux'] = stristr($HTTP_USER_AGENT, 'linux');
+ $bw['unix'] = stristr($HTTP_USER_AGENT, 'unix');
+
+ $bw['ns4'] = stristr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie');
+ $bw['ns'] = ($bw['ns4'] || stristr($HTTP_USER_AGENT, 'netscape'));
+ $bw['ie'] = stristr($HTTP_USER_AGENT, 'msie');
+ $bw['mz'] = stristr($HTTP_USER_AGENT, 'mozilla/5');
+ $bw['opera'] = stristr($HTTP_USER_AGENT, 'opera');
+ $bw['safari'] = stristr($HTTP_USER_AGENT, 'safari');
+
+ if($bw['ns'])
+ {
+ $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+ $bw['ver'] = $test ? (float)$regs[1] : 0;
+ }
+ if($bw['mz'])
+ {
+ $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+ $bw['ver'] = $test ? (float)$regs[1] : 0;
+ }
+ if($bw['ie'])
+ {
+ $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+ $bw['ver'] = $test ? (float)$regs[1] : 0;
+ }
+ if($bw['opera'])
+ {
+ $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+ $bw['ver'] = $test ? (float)$regs[1] : 0;
+ }
+
+ if(eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs))
+ $bw['lang'] = $regs[1];
+ else
+ $bw['lang'] = 'en';
+
+ $bw['dom'] = ($bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5) || ($bw['opera'] && $bw['ver']>=7));
+ $bw['pngalpha'] = $bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5.5) ||
+ ($bw['ie'] && $bw['ver']>=5 && $bw['mac']) || ($bw['opera'] && $bw['ver']>=7) ? TRUE : FALSE;
+
+ return $bw;
+ }
+
+
+// get text in the desired language from the language file
+function rcube_label($attrib)
+ {
+ global $sess_user_lang, $INSTALL_PATH;
+ static $sa_text_data, $s_language;
+
+ // extract attributes
+ if (is_string($attrib))
+ $attrib = array('name' => $attrib);
+
+ $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1;
+ $vars = isset($attrib['vars']) ? $attrib['vars'] : '';
+
+ $command_name = strlen($attrib['command']) ? $attrib['command'] : NULL;
+ $alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : '');
+
+
+ // load localized texts
+ if (!$sa_text_data || $s_language != $sess_user_lang)
+ {
+ $sa_text_data = array();
+
+ // get english labels (these should be complete)
+ @include($INSTALL_PATH.'program/localization/en/labels.inc');
+ @include($INSTALL_PATH.'program/localization/en/messages.inc');
+
+ if (is_array($labels))
+ $sa_text_data = $labels;
+ if (is_array($messages))
+ $sa_text_data = array_merge($sa_text_data, $messages);
+
+ // include user language files
+ if ($sess_user_lang!='en' && is_dir($INSTALL_PATH.'program/localization/'.$sess_user_lang))
+ {
+ include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/labels.inc');
+ include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/messages.inc');
+
+ if (is_array($labels))
+ $sa_text_data = array_merge($sa_text_data, $labels);
+ if (is_array($messages))
+ $sa_text_data = array_merge($sa_text_data, $messages);
+ }
+
+ $s_language = $sess_user_lang;
+ }
+
+ // text does not exist
+ if (!($text_item = $sa_text_data[$alias]))
+ {
+ /*
+ raise_error(array('code' => 500,
+ 'type' => 'php',
+ 'line' => __LINE__,
+ 'file' => __FILE__,
+ 'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE);
+ */
+ return "[$alias]";
+ }
+
+ // make text item array
+ $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item);
+
+ // decide which text to use
+ if ($nr==1)
+ $text = $a_text_item['single'];
+ else if ($nr>0)
+ $text = $a_text_item['multiple'];
+ else if ($nr==0)
+ {
+ if ($a_text_item['none'])
+ $text = $a_text_item['none'];
+ else if ($a_text_item['single'])
+ $text = $a_text_item['single'];
+ else if ($a_text_item['multiple'])
+ $text = $a_text_item['multiple'];
+ }
+
+ // default text is single
+ if ($text=='')
+ $text = $a_text_item['single'];
+
+
+ // replace vars in text
+ if (is_array($attrib['vars']))
+ {
+ foreach ($attrib['vars'] as $var_key=>$var_value)
+ $a_replace_vars[substr($var_key, 0, 1)=='$' ? substr($var_key, 1) : $var_key] = $var_value;
+ }
+
+ if ($a_replace_vars)
+ $text = preg_replace('/\${?([_a-z]{1}[_a-z0-9]*)}?/ei', '$a_replace_vars["\1"]', $text);
+
+ // remove variables in text which were not available in arg $vars and $nr
+ eval("\$text = <<<EOF
+$text
+EOF;
+");
+
+
+ // format output
+ if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])
+ return ucfirst($text);
+ else if ($attrib['uppercase'])
+ return strtoupper($text);
+ else if ($attrib['lowercase'])
+ return strtolower($text);
+ else
+ return $text;
+
+ return $text;
+ }
+
+
+// send HTTP header for no-cacheing steps
+function send_nocacheing_headers()
+ {
+ if (headers_sent())
+ return;
+
+ header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
+ header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
+ header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
+ header("Pragma: no-cache");
+ }
+
+
+// send header with expire date 30 days in future
+function send_future_expire_header()
+ {
+ if (!headers_sent())
+ header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+2600000)." GMT");
+ }
+
+
+// replace specials characters to a specific encoding type
+function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
+ {
+ global $OUTPUT_TYPE;
+ static $html_encode_arr, $js_rep_table, $rtf_rep_table, $xml_rep_table;
+
+ if (!$enctype)
+ $enctype = $GLOBALS['OUTPUT_TYPE'];
+
+ // convert nbsps back to normal spaces if not html
+ if ($enctype!='html')
+ $str = str_replace(chr(160), ' ', $str);
+
+
+ // encode for plaintext
+ if ($enctype=='text')
+ return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
+
+ // encode for HTML output
+ if ($enctype=='html')
+ {
+ if (!$html_encode_arr)
+ {
+ $html_encode_arr = get_html_translation_table(HTML_ENTITIES);
+ $html_encode_arr["?"] = '&#150;';
+ $html_encode_arr[chr(128)] = '&euro;';
+ unset($html_encode_arr['?']);
+ unset($html_encode_arr['&']);
+ }
+
+ $ltpos = strpos($str, '<');
+ $encode_arr = $html_encode_arr;
+
+ // don't replace quotes and html tags
+ if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false)
+ {
+ unset($encode_arr['"']);
+ unset($encode_arr['<']);
+ unset($encode_arr['>']);
+ }
+ else if ($mode=='remove')
+ $str = strip_tags($str);
+
+ $out = strtr($str, $encode_arr);
+
+ return $newlines ? nl2br($out) : $out;
+ }
+
+
+ if ($enctype=='url')
+ return rawurlencode($str);
+
+
+ // if the replace tables for RTF, XML and JS are not yet defined
+ if (!$js_rep_table)
+ {
+ for ($c=160; $c<256; $c++) // can be increased to support more charsets
+ {
+ $hex = dechex($c);
+ $js_rep_table[Chr($c)] = sprintf("\u%s%s", str_repeat('0', 4-strlen($hex)), $hex);
+ $rtf_rep_table[Chr($c)] = "\\'$hex";
+ $xml_rep_table[Chr($c)] = "&#$c;";
+ }
+
+ $js_rep_table['"'] = sprintf("\u%s%s", str_repeat('0', 4-strlen(dechex(34))), dechex(34));
+ $xml_rep_table['"'] = '&quot;';
+ }
+
+ // encode for RTF
+ if ($enctype=='xml')
+ return strtr($str, $xml_rep_table);
+
+ // encode for javascript use
+ if ($enctype=='js')
+ return preg_replace(array("/\r\n/", '/"/', "/'/"), array('\n', '\"', "\'"), strtr($str, $js_rep_table));
+
+ // encode for RTF
+ if ($enctype=='rtf')
+ return preg_replace("/\r\n/", "\par ", strtr($str, $rtf_rep_table));
+
+ // no encoding given -> return original string
+ return $str;
+ }
+
+
+function decode_specialchars($input, $charset='')
+ {
+ $charset = strtolower($charset);
+
+ if (strcasecmp($charset, 'utf-8')==0)
+ return utf8_decode($input);
+ else if ($charset=="koi8-r")
+ return convert_cyr_string($input, 'k', 'w');
+ else if ($charset=="iso8859-5")
+ return convert_cyr_string($input, 'i', 'w');
+ else if ($charset=="x-cp866")
+ return convert_cyr_string($input, 'a', 'w');
+ else if ($charset=="x-mac-cyrillic")
+ return convert_cyr_string($input, 'm', 'w');
+
+ return $input;
+ }
+
+
+
+// function to convert an array to a javascript array
+function array2js($arr, $type='')
+ {
+ if (!$type)
+ $type = 'mixed';
+
+ if (is_array($arr))
+ {
+ // no items in array
+ if (!sizeof($arr))
+ return 'new Array()';
+ else
+ {
+ $a_pairs = array();
+ $keys_arr = array_keys($arr);
+ $is_assoc = $have_numeric = 0;
+
+ for ($i=0; $i<sizeof($keys_arr); ++$i)
+ {
+ if(is_numeric($keys_arr[$i]))
+ $have_numeric = 1;
+ if (!is_numeric($keys_arr[$i]) || $keys_arr[$i]!=$i)
+ $is_assoc = 1;
+ if($is_assoc && $have_numeric)
+ break;
+ }
+
+ $previous_was_array = false;
+ while (list($key, $value) = each($arr))
+ {
+ // enclose key with quotes if it is not variable-name conform
+ if (!ereg("^[_a-zA-Z]{1}[_a-zA-Z0-9]*$", $key) /* || is_js_reserved_word($key) */)
+ $key = "'$key'";
+
+ if (!is_array($value))
+ {
+ $value = str_replace("\r\n", '\n', $value);
+ $value = str_replace("\n", '\n', $value);
+ }
+
+ $is_string = false;
+ if (!is_array($value))
+ {
+ if ($type=='string')
+ $is_string = true;
+ else if ((($type=='mixed' && is_numeric($value)) || $type=='int') && strlen($value)<16) // js interprets numbers with digits >15 as ...e+...
+ $is_string = FALSE;
+ else
+ $is_string = TRUE;
+ }
+
+ if ($is_string)
+ $value = "'".preg_replace("/(?<!\\\)'/", "\'", $value)."'";
+
+ $a_pairs[] = sprintf("%s%s",
+ $is_assoc ? "$key:" : '',
+ is_array($value) ? array2js($value, $type) : $value);
+ }
+
+ if ($a_pairs)
+ {
+ if ($is_assoc)
+ $return = '{'.implode(',', $a_pairs).'}';
+ else
+ $return = '['.implode(',', $a_pairs).']';
+ }
+
+ return $return;
+ }
+ }
+ else
+ return $arr;
+ }
+
+
+// similar function as in_array() ut case-insensitive
+function in_array_nocase($needle, $haystack)
+ {
+ foreach ($haystack as $value)
+ {
+ if (strtolower($needle)===strtolower($value))
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+
+
+// find out if the string content means TRUE or FALSE
+function get_boolean($str)
+ {
+ $str = strtolower($str);
+ if(in_array($str, array('false', '0', 'no', 'nein', ''), TRUE))
+ return FALSE;
+ else
+ return TRUE;
+ }
+
+
+function show_bytes($numbytes)
+ {
+ if ($numbytes > 1024)
+ return sprintf('%d KB', round($numbytes/1024));
+ else
+ return sprintf('%d B', $numbytes);
+ }
+
+
+// convert paths like ../xxx to an absolute path using a base url
+function make_absolute_url($path, $base_url)
+ {
+ $host_url = $base_url;
+ $abs_path = $path;
+
+ // cut base_url to the last directory
+ if (strpos($base_url, '/')>7)
+ {
+ $host_url = substr($base_url, 0, strpos($base_url, '/'));
+ $base_url = substr($base_url, 0, strrpos($base_url, '/'));
+ }
+
+ // $path is absolute
+ if ($path{0}=='/')
+ $abs_path = $host_url.$path;
+ else
+ {
+ // strip './' because its the same as ''
+ $path = preg_replace('/^\.\//', '', $path);
+
+ if(preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER))
+ foreach($matches as $a_match)
+ {
+ if (strrpos($base_url, '/'))
+ $base_url = substr($base_url, 0, strrpos($base_url, '/'));
+
+ $path = substr($path, 3);
+ }
+
+ $abs_path = $base_url.'/'.$path;
+ }
+
+ return $abs_path;
+ }
+
+
+
+?> \ No newline at end of file