From ab0b51a1fef87bcc643c3aaf2e635c811b28ccd8 Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Tue, 15 Feb 2011 06:10:59 -0500
Subject: [PATCH] - Use only one from IMAP authentication methods to prevent login delays (1487784)

---
 program/include/rcmail.php |  253 +++++++++++++++++++++++++++++++++++++------------
 1 files changed, 189 insertions(+), 64 deletions(-)

diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index aa9f564..1c98106 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -114,7 +114,8 @@
   public $comm_path = './';
 
   private $texts;
-  private $books = array();
+  private $address_books = array();
+  private $action_map = array();
 
 
   /**
@@ -330,6 +331,10 @@
     if ($plugin['instance'] instanceof rcube_addressbook) {
       $contacts = $plugin['instance'];
     }
+    // use existing instance
+    else if (isset($this->address_books[$id]) && is_a($this->address_books[$id], 'rcube_addressbook') && (!$writeable || !$this->address_books[$id]->readonly)) {
+      $contacts = $this->address_books[$id];
+    }
     else if ($id && $ldap_config[$id]) {
       $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host']));
     }
@@ -350,8 +355,8 @@
     }
 
     // add to the 'books' array for shutdown function
-    if (!in_array($contacts, $this->books))
-      $this->books[] = $contacts;
+    if (!isset($this->address_books[$id]))
+      $this->address_books[$id] = $contacts;
 
     return $contacts;
   }
@@ -372,11 +377,12 @@
 
     // We are using the DB address book
     if ($abook_type != 'ldap') {
-      $contacts = new rcube_contacts($this->db, null);
+      if (!isset($this->address_books['0']))
+        $this->address_books['0'] = new rcube_contacts($this->db, $this->user->ID);
       $list['0'] = array(
-        'id' => 0,
+        'id' => '0',
         'name' => rcube_label('personaladrbook'),
-        'groups' => $contacts->groups,
+        'groups' => $this->address_books['0']->groups,
         'readonly' => false,
         'autocomplete' => in_array('sql', $autocomplete)
       );
@@ -388,7 +394,7 @@
         $list[$id] = array(
           'id' => $id,
           'name' => $prop['name'],
-          'groups' => false,
+          'groups' => is_array($prop['groups']),
           'readonly' => !$prop['writable'],
           'autocomplete' => in_array('sql', $autocomplete)
         );
@@ -397,14 +403,15 @@
     $plugin = $this->plugins->exec_hook('addressbooks_list', array('sources' => $list));
     $list = $plugin['sources'];
 
-    if ($writeable && !empty($list)) {
-      foreach ($list as $idx => $item) {
-        if ($item['readonly']) {
+    foreach ($list as $idx => $item) {
+      // register source for shutdown function
+      if (!is_object($this->address_books[$item['id']]))
+        $this->address_books[$item['id']] = $item;
+      // remove from list if not writeable as requested
+      if ($writeable && $item['readonly'])
           unset($list[$idx]);
-        }
-      }
     }
-
+    
     return $list;
   }
 
@@ -592,10 +599,8 @@
       session_start();
 
     // set initial session vars
-    if (!isset($_SESSION['auth_time'])) {
-      $_SESSION['auth_time'] = time();
+    if (!$_SESSION['user_id'])
       $_SESSION['temp'] = true;
-    }
   }
 
 
@@ -617,6 +622,9 @@
       $keep_alive = max(60, $keep_alive);
       $this->session->set_keep_alive($keep_alive);
     }
+    
+    $this->session->set_secret($this->config->get('des_key') . $_SERVER['HTTP_USER_AGENT']);
+    $this->session->set_ip_check($this->config->get('ip_check'));
   }
 
 
@@ -673,9 +681,9 @@
     // Check if we need to add domain
     if (!empty($config['username_domain']) && strpos($username, '@') === false) {
       if (is_array($config['username_domain']) && isset($config['username_domain'][$host]))
-        $username .= '@'.rcube_parse_host($config['username_domain'][$host]);
+        $username .= '@'.rcube_parse_host($config['username_domain'][$host], $host);
       else if (is_string($config['username_domain']))
-        $username .= '@'.rcube_parse_host($config['username_domain']);
+        $username .= '@'.rcube_parse_host($config['username_domain'], $host);
     }
 
     // Convert username to lowercase. If IMAP backend
@@ -691,12 +699,12 @@
 
     // Here we need IDNA ASCII
     // Only rcube_contacts class is using domain names in Unicode
-    $host = idn_to_ascii($host);
+    $host = rcube_idn_to_ascii($host);
     if (strpos($username, '@')) {
       // lowercase domain name
       list($local, $domain) = explode('@', $username);
       $username = $local . '@' . mb_strtolower($domain);
-      $username = idn_to_ascii($username);
+      $username = rcube_idn_to_ascii($username);
     }
 
     // user already registered -> overwrite username
@@ -760,6 +768,7 @@
     // login succeeded
     if (is_object($user) && $user->ID) {
       $this->set_user($user);
+      $this->session_configure();
 
       // set session vars
       $_SESSION['user_id']   = $user->ID;
@@ -769,7 +778,7 @@
       $_SESSION['imap_ssl']  = $imap_ssl;
       $_SESSION['password']  = $this->encrypt($pass);
       $_SESSION['login_time'] = mktime();
-
+      
       if (isset($_REQUEST['_timezone']) && $_REQUEST['_timezone'] != '_default_')
         $_SESSION['timezone'] = floatval($_REQUEST['_timezone']);
 
@@ -917,6 +926,22 @@
 
 
   /**
+   * Check if the given text lable exists
+   *
+   * @param string Label name
+   * @return boolean True if text exists (either in the current language or in en_US)
+   */
+  public function text_exists($name, $domain=null)
+  {
+    // load localization files if not done yet
+    if (empty($this->texts))
+      $this->load_language();
+
+    // check for text with domain first
+    return ($domain && isset($this->texts[$domain.'.'.$name])) || isset($this->texts[$name]);
+  }
+
+  /**
    * Load a localization package
    *
    * @param string Language ID
@@ -992,50 +1017,14 @@
 
 
   /**
-   * Check the auth hash sent by the client against the local session credentials
-   *
-   * @return boolean True if valid, False if not
-   */
-  function authenticate_session()
-  {
-    // advanced session authentication
-    if ($this->config->get('double_auth')) {
-      $now = time();
-      $valid = ($_COOKIE['sessauth'] == $this->get_auth_hash(session_id(), $_SESSION['auth_time']) ||
-                $_COOKIE['sessauth'] == $this->get_auth_hash(session_id(), $_SESSION['last_auth']));
-
-      // renew auth cookie every 5 minutes (only for GET requests)
-      if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now - $_SESSION['auth_time'] > 300)) {
-        $_SESSION['last_auth'] = $_SESSION['auth_time'];
-        $_SESSION['auth_time'] = $now;
-        rcmail::setcookie('sessauth', $this->get_auth_hash(session_id(), $now), 0);
-      }
-    }
-    else {
-      $valid = $this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] == $this->session->get_ip() : true;
-    }
-
-    // check session filetime
-    $lifetime = $this->config->get('session_lifetime');
-    $sess_ts = $this->session->get_ts();
-    if (!empty($lifetime) && !empty($sess_ts) && $sess_ts + $lifetime*60 < time()) {
-      $valid = false;
-    }
-
-    return $valid;
-  }
-
-
-  /**
    * Destroy session data and remove cookie
    */
   public function kill_session()
   {
     $this->plugins->exec_hook('session_destroy');
 
-    $this->session->remove();
-    $_SESSION = array('language' => $this->user->language, 'auth_time' => time(), 'temp' => true);
-    rcmail::setcookie('sessauth', '-del-', time() - 60);
+    $this->session->kill();
+    $_SESSION = array('language' => $this->user->language, 'temp' => true);
     $this->user->reset();
   }
 
@@ -1049,7 +1038,7 @@
 
     // on logout action we're not connected to imap server
     if (($config['logout_purge'] && !empty($config['trash_mbox'])) || $config['logout_expunge']) {
-      if (!$this->authenticate_session())
+      if (!$this->session->check_auth())
         return;
 
       $this->imap_connect();
@@ -1077,9 +1066,12 @@
     if (is_object($this->smtp))
       $this->smtp->disconnect();
 
-    foreach ($this->books as $book)
-      if (is_object($book))
+    foreach ($this->address_books as $book) {
+      if (!is_object($book))  // maybe an address book instance wasn't fetched using get_address_book() yet
+        $book = $this->get_address_book($book['id']);
+      if (is_a($book, 'rcube_addressbook'))
         $book->close();
+    }
 
     // before closing the database connection, write session data
     if ($_SERVER['REMOTE_ADDR'])
@@ -1306,6 +1298,112 @@
 
 
   /**
+   * 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
@@ -1322,6 +1420,33 @@
     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';
+  }
+
 }
-
-

--
Gitblit v1.9.1