+ /**
+ * Generates encryption initialization vector (IV)
+ *
+ * @param int Vector size
+ * @return string Vector string
+ */
+ private function create_iv($size)
+ {
+ // mcrypt_create_iv() can be slow when system lacks entrophy
+ // we'll generate IV vector manually
+ $iv = '';
+ for ($i = 0; $i < $size; $i++)
+ $iv .= chr(mt_rand(0, 255));
+ return $iv;
+ }
+
+ /**
+ * Build a valid URL to this instance of Roundcube
+ *
+ * @param mixed Either a string with the action or url parameters as key-value pairs
+ * @return string Valid application URL
+ */
+ public function url($p)
+ {
+ if (!is_array($p))
+ $p = array('_action' => @func_get_arg(0));
+
+ $task = $p['_task'] ? $p['_task'] : ($p['task'] ? $p['task'] : $this->task);
+ $p['_task'] = $task;
+ unset($p['task']);
+
+ $url = './';
+ $delm = '?';
+ foreach (array_reverse($p) as $key => $val) {
+ if ($val !== '') {
+ $par = $key[0] == '_' ? $key : '_'.$key;
+ $url .= $delm.urlencode($par).'='.urlencode($val);
+ $delm = '&';
+ }
+ }
+ return $url;
+ }
+
+
+ /**
+ * Use imagemagick or GD lib to read image properties
+ *
+ * @param string Absolute file path
+ * @return mixed Hash array with image props like type, width, height or False on error
+ */
+ public static function imageprops($filepath)
+ {
+ $rcmail = rcmail::get_instance();
+ if ($cmd = $rcmail->config->get('im_identify_path', false)) {
+ list(, $type, $size) = explode(' ', strtolower(rcmail::exec($cmd. ' 2>/dev/null {in}', array('in' => $filepath))));
+ if ($size)
+ list($width, $height) = explode('x', $size);
+ }
+ else if (function_exists('getimagesize')) {
+ $imsize = @getimagesize($filepath);
+ $width = $imsize[0];
+ $height = $imsize[1];
+ $type = preg_replace('!image/!', '', $imsize['mime']);
+ }
+
+ return $type ? array('type' => $type, 'width' => $width, 'height' => $height) : false;
+ }
+
+
+ /**
+ * Convert an image to a given size and type using imagemagick (ensures input is an image)
+ *
+ * @param $p['in'] Input filename (mandatory)
+ * @param $p['out'] Output filename (mandatory)
+ * @param $p['size'] Width x height of resulting image, e.g. "160x60"
+ * @param $p['type'] Output file type, e.g. "jpg"
+ * @param $p['-opts'] Custom command line options to ImageMagick convert
+ * @return Success of convert as true/false
+ */
+ public static function imageconvert($p)
+ {
+ $result = false;
+ $rcmail = rcmail::get_instance();
+ $convert = $rcmail->config->get('im_convert_path', false);
+ $identify = $rcmail->config->get('im_identify_path', false);
+
+ // imagemagick is required for this
+ if (!$convert)
+ return false;
+
+ if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false))))
+ list(, $type) = explode(' ', strtolower(rcmail::exec($identify . ' 2>/dev/null {in}', $p))); # for things like eps
+
+ $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
+ $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75);
+ $p['-opts'] = array('-resize' => $p['size'].'>') + (array)$p['-opts'];
+
+ if (in_array($type, explode(',', $p['types']))) # Valid type?
+ $result = rcmail::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === "";
+
+ return $result;
+ }
+
+
+ /**
+ * Construct shell command, execute it and return output as string.
+ * Keywords {keyword} are replaced with arguments
+ *
+ * @param $cmd Format string with {keywords} to be replaced
+ * @param $values (zero, one or more arrays can be passed)
+ * @return output of command. shell errors not detectable
+ */
+ public static function exec(/* $cmd, $values1 = array(), ... */)
+ {
+ $args = func_get_args();
+ $cmd = array_shift($args);
+ $values = $replacements = array();
+
+ // merge values into one array
+ foreach ($args as $arg)
+ $values += (array)$arg;
+
+ preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER);
+ foreach ($matches as $tags) {
+ list(, $tag, $option, $key) = $tags;
+ $parts = array();
+
+ if ($option) {
+ foreach ((array)$values["-$key"] as $key => $value) {
+ if ($value === true || $value === false || $value === null)
+ $parts[] = $value ? $key : "";
+ else foreach ((array)$value as $val)
+ $parts[] = "$key " . escapeshellarg($val);
+ }
+ }
+ else {
+ foreach ((array)$values[$key] as $value)
+ $parts[] = escapeshellarg($value);
+ }
+
+ $replacements[$tag] = join(" ", $parts);
+ }
+
+ // use strtr behaviour of going through source string once
+ $cmd = strtr($cmd, $replacements);
+
+ return (string)shell_exec($cmd);
+ }
+
+
+ /**
+ * Helper method to set a cookie with the current path and host settings
+ *
+ * @param string Cookie name
+ * @param string Cookie value
+ * @param string Expiration time
+ */
+ public static function setcookie($name, $value, $exp = 0)
+ {
+ if (headers_sent())
+ return;
+
+ $cookie = session_get_cookie_params();
+
+ setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'],
+ rcube_https_check(), true);
+ }
+
+ /**
+ * Registers action aliases for current task
+ *
+ * @param array $map Alias-to-filename hash array
+ */
+ public function register_action_map($map)
+ {
+ if (is_array($map)) {
+ foreach ($map as $idx => $val) {
+ $this->action_map[$idx] = $val;
+ }
+ }
+ }
+
+ /**
+ * Returns current action filename
+ *
+ * @param array $map Alias-to-filename hash array
+ */
+ public function get_action_file()
+ {
+ if (!empty($this->action_map[$this->action])) {
+ return $this->action_map[$this->action];
+ }
+
+ return strtr($this->action, '-', '_') . '.inc';
+ }
+
+ /**
+ * Fixes some user preferences according to namespace handling change.
+ * Old Roundcube versions were using folder names with removed namespace prefix.
+ * Now we need to add the prefix on servers where personal namespace has prefix.
+ *
+ * @param rcube_user $user User object
+ */
+ private function fix_namespace_settings($user)
+ {
+ $prefix = $this->imap->get_namespace('prefix');
+ $prefix_len = strlen($prefix);
+
+ if (!$prefix_len)
+ return;