Ignore:
Timestamp:
Feb 15, 2012 5:02:48 AM (15 months ago)
Author:
thomasb
Message:

Split rcmail functionality into rcube base class (framework) and keep application specific stuff in rcmail

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/devel-framework/roundcubemail/program/include/rcmail.php

    r5866 r5881  
    2828 * @package Core 
    2929 */ 
    30 class rcmail 
     30class rcmail extends rcube 
    3131{ 
    3232  /** 
     
    3636   */ 
    3737  static public $main_tasks = array('mail','settings','addressbook','login','logout','utils','dummy'); 
    38  
    39   /** 
    40    * Singleton instace of rcmail 
    41    * 
    42    * @var rcmail 
    43    */ 
    44   static private $instance; 
    45  
    46   /** 
    47    * Stores instance of rcube_config. 
    48    * 
    49    * @var rcube_config 
    50    */ 
    51   public $config; 
    52  
    53   /** 
    54    * Stores rcube_user instance. 
    55    * 
    56    * @var rcube_user 
    57    */ 
    58   public $user; 
    59  
    60   /** 
    61    * Instace of database class. 
    62    * 
    63    * @var rcube_mdb2 
    64    */ 
    65   public $db; 
    66  
    67   /** 
    68    * Instace of Memcache class. 
    69    * 
    70    * @var rcube_mdb2 
    71    */ 
    72   public $memcache; 
    73  
    74   /** 
    75    * Instace of rcube_session class. 
    76    * 
    77    * @var rcube_session 
    78    */ 
    79   public $session; 
    80  
    81   /** 
    82    * Instance of rcube_smtp class. 
    83    * 
    84    * @var rcube_smtp 
    85    */ 
    86   public $smtp; 
    87  
    88   /** 
    89    * Instance of rcube_storage class. 
    90    * 
    91    * @var rcube_storage 
    92    */ 
    93   public $storage; 
    94  
    95   /** 
    96    * Instance of rcube_output class. 
    97    * 
    98    * @var rcube_output 
    99    */ 
    100   public $output; 
    101  
    102   /** 
    103    * Instance of rcube_plugin_api. 
    104    * 
    105    * @var rcube_plugin_api 
    106    */ 
    107   public $plugins; 
    10838 
    10939  /** 
     
    12252  public $comm_path = './'; 
    12353 
    124   private $texts; 
    12554  private $address_books = array(); 
    126   private $caches = array(); 
    12755  private $action_map = array(); 
    128   private $shutdown_functions = array(); 
    12956 
    13057 
     
    13663  static function get_instance() 
    13764  { 
    138     if (!self::$instance) { 
     65    if (!self::$instance || !is_a(self::$instance, 'rcmail')) { 
    13966      self::$instance = new rcmail(); 
    14067      self::$instance->startup();  // init AFTER object was linked with self::$instance 
     
    14673 
    14774  /** 
    148    * Private constructor 
    149    */ 
    150   private function __construct() 
    151   { 
    152     // load configuration 
    153     $this->config = new rcube_config(); 
    154  
    155     register_shutdown_function(array($this, 'shutdown')); 
    156   } 
    157  
    158  
    159   /** 
    16075   * Initial startup function 
    16176   * to register session, create database and imap connections 
    16277   */ 
    163   private function startup() 
    164   { 
    165     // initialize syslog 
    166     if ($this->config->get('log_driver') == 'syslog') { 
    167       $syslog_id = $this->config->get('syslog_id', 'roundcube'); 
    168       $syslog_facility = $this->config->get('syslog_facility', LOG_USER); 
    169       openlog($syslog_id, LOG_ODELAY, $syslog_facility); 
    170     } 
    171  
    172     // connect to database 
    173     $this->get_dbh(); 
     78  protected function startup() 
     79  { 
     80    $this->init(self::INIT_WITH_DB | self::INIT_WITH_PLUGINS); 
    17481 
    17582    // start session 
     
    200107      $GLOBALS['OUTPUT'] = $this->load_gui(!empty($_REQUEST['_framed'])); 
    201108 
    202     // create plugin API and load plugins 
    203     $this->plugins = rcube_plugin_api::get_instance(); 
    204  
    205     // init plugins 
    206     $this->plugins->init(); 
     109    // load plugins 
     110    $this->plugins->init($this, $this->task); 
     111    $this->plugins->load_plugins((array)$this->config->get('plugins', array()), array('filesystem_attachments', 'jqueryui')); 
    207112  } 
    208113 
     
    252157    if (in_array($_SESSION['language'], array('tr_TR', 'ku', 'az_AZ'))) 
    253158      setlocale(LC_CTYPE, 'en_US' . '.utf8'); 
    254   } 
    255  
    256  
    257   /** 
    258    * Check the given string and return a valid language code 
    259    * 
    260    * @param string Language code 
    261    * @return string Valid language code 
    262    */ 
    263   private function language_prop($lang) 
    264   { 
    265     static $rcube_languages, $rcube_language_aliases; 
    266  
    267     // user HTTP_ACCEPT_LANGUAGE if no language is specified 
    268     if (empty($lang) || $lang == 'auto') { 
    269        $accept_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); 
    270        $lang = str_replace('-', '_', $accept_langs[0]); 
    271      } 
    272  
    273     if (empty($rcube_languages)) { 
    274       @include(INSTALL_PATH . 'program/localization/index.inc'); 
    275     } 
    276  
    277     // check if we have an alias for that language 
    278     if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang])) { 
    279       $lang = $rcube_language_aliases[$lang]; 
    280     } 
    281     // try the first two chars 
    282     else if (!isset($rcube_languages[$lang])) { 
    283       $short = substr($lang, 0, 2); 
    284  
    285       // check if we have an alias for the short language code 
    286       if (!isset($rcube_languages[$short]) && isset($rcube_language_aliases[$short])) { 
    287         $lang = $rcube_language_aliases[$short]; 
    288       } 
    289       // expand 'nn' to 'nn_NN' 
    290       else if (!isset($rcube_languages[$short])) { 
    291         $lang = $short.'_'.strtoupper($short); 
    292       } 
    293     } 
    294  
    295     if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) { 
    296       $lang = 'en_US'; 
    297     } 
    298  
    299     return $lang; 
    300   } 
    301  
    302  
    303   /** 
    304    * Get the current database connection 
    305    * 
    306    * @return rcube_mdb2  Database connection object 
    307    */ 
    308   public function get_dbh() 
    309   { 
    310     if (!$this->db) { 
    311       $config_all = $this->config->all(); 
    312  
    313       $this->db = new rcube_mdb2($config_all['db_dsnw'], $config_all['db_dsnr'], $config_all['db_persistent']); 
    314       $this->db->sqlite_initials = INSTALL_PATH . 'SQL/sqlite.initial.sql'; 
    315       $this->db->set_debug((bool)$config_all['sql_debug']); 
    316     } 
    317  
    318     return $this->db; 
    319   } 
    320  
    321  
    322   /** 
    323    * Get global handle for memcache access 
    324    * 
    325    * @return object Memcache 
    326    */ 
    327   public function get_memcache() 
    328   { 
    329     if (!isset($this->memcache)) { 
    330       // no memcache support in PHP 
    331       if (!class_exists('Memcache')) { 
    332         $this->memcache = false; 
    333         return false; 
    334       } 
    335  
    336       $this->memcache = new Memcache; 
    337       $this->mc_available = 0; 
    338  
    339       // add alll configured hosts to pool 
    340       $pconnect = $this->config->get('memcache_pconnect', true); 
    341       foreach ($this->config->get('memcache_hosts', array()) as $host) { 
    342         list($host, $port) = explode(':', $host); 
    343         if (!$port) $port = 11211; 
    344         $this->mc_available += intval($this->memcache->addServer($host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure'))); 
    345       } 
    346  
    347       // test connection and failover (will result in $this->mc_available == 0 on complete failure) 
    348       $this->memcache->increment('__CONNECTIONTEST__', 1);  // NOP if key doesn't exist 
    349  
    350       if (!$this->mc_available) 
    351         $this->memcache = false; 
    352     } 
    353  
    354     return $this->memcache; 
    355   } 
    356  
    357  
    358   /** 
    359    * Callback for memcache failure 
    360    */ 
    361   public function memcache_failure($host, $port) 
    362   { 
    363     static $seen = array(); 
    364  
    365     // only report once 
    366     if (!$seen["$host:$port"]++) { 
    367       $this->mc_available--; 
    368       self::raise_error(array('code' => 604, 'type' => 'db', 
    369         'line' => __LINE__, 'file' => __FILE__, 
    370         'message' => "Memcache failure on host $host:$port"), 
    371         true, false); 
    372     } 
    373   } 
    374  
    375  
    376   /** 
    377    * Initialize and get cache object 
    378    * 
    379    * @param string $name   Cache identifier 
    380    * @param string $type   Cache type ('db', 'apc' or 'memcache') 
    381    * @param int    $ttl    Expiration time for cache items in seconds 
    382    * @param bool   $packed Enables/disables data serialization 
    383    * 
    384    * @return rcube_cache Cache object 
    385    */ 
    386   public function get_cache($name, $type='db', $ttl=0, $packed=true) 
    387   { 
    388     if (!isset($this->caches[$name])) { 
    389       $this->caches[$name] = new rcube_cache($type, $_SESSION['user_id'], $name, $ttl, $packed); 
    390     } 
    391  
    392     return $this->caches[$name]; 
    393159  } 
    394160 
     
    566332 
    567333  /** 
    568    * Create SMTP object and connect to server 
    569    * 
    570    * @param boolean True if connection should be established 
    571    */ 
    572   public function smtp_init($connect = false) 
    573   { 
    574     $this->smtp = new rcube_smtp(); 
    575  
    576     if ($connect) 
    577       $this->smtp->connect(); 
    578   } 
    579  
    580  
    581   /** 
    582    * Initialize and get storage object 
    583    * 
    584    * @return rcube_storage Storage object 
    585    */ 
    586   public function get_storage() 
    587   { 
    588     // already initialized 
    589     if (!is_object($this->storage)) { 
    590       $this->storage_init(); 
    591     } 
    592  
    593     return $this->storage; 
    594   } 
    595  
    596  
    597   /** 
    598    * Connect to the IMAP server with stored session data. 
    599    * 
    600    * @return bool True on success, False on error 
    601    * @deprecated 
    602    */ 
    603   public function imap_connect() 
    604   { 
    605     return $this->storage_connect(); 
    606   } 
    607  
    608  
    609   /** 
    610    * Initialize IMAP object. 
    611    * 
    612    * @deprecated 
    613    */ 
    614   public function imap_init() 
    615   { 
    616     $this->storage_init(); 
    617   } 
    618  
    619  
    620   /** 
    621    * Initialize storage object 
    622    */ 
    623   public function storage_init() 
    624   { 
    625     // already initialized 
    626     if (is_object($this->storage)) { 
    627       return; 
    628     } 
    629  
    630     $driver = $this->config->get('storage_driver', 'imap'); 
    631     $driver_class = "rcube_{$driver}"; 
    632  
    633     if (!class_exists($driver_class)) { 
    634       self::raise_error(array( 
    635         'code' => 700, 'type' => 'php', 
    636         'file' => __FILE__, 'line' => __LINE__, 
    637         'message' => "Storage driver class ($driver) not found!"), 
    638         true, true); 
    639     } 
    640  
    641     // Initialize storage object 
    642     $this->storage = new $driver_class; 
    643  
    644     // for backward compat. (deprecated, will be removed) 
    645     $this->imap = $this->storage; 
    646  
    647     // enable caching of mail data 
    648     $storage_cache  = $this->config->get("{$driver}_cache"); 
    649     $messages_cache = $this->config->get('messages_cache'); 
    650     // for backward compatybility 
    651     if ($storage_cache === null && $messages_cache === null && $this->config->get('enable_caching')) { 
    652         $storage_cache  = 'db'; 
    653         $messages_cache = true; 
    654     } 
    655  
    656     if ($storage_cache) 
    657         $this->storage->set_caching($storage_cache); 
    658     if ($messages_cache) 
    659         $this->storage->set_messages_caching(true); 
    660  
    661     // set pagesize from config 
    662     $pagesize = $this->config->get('mail_pagesize'); 
    663     if (!$pagesize) { 
    664         $pagesize = $this->config->get('pagesize', 50); 
    665     } 
    666     $this->storage->set_pagesize($pagesize); 
    667  
    668     // set class options 
    669     $options = array( 
    670       'auth_type'   => $this->config->get("{$driver}_auth_type", 'check'), 
    671       'auth_cid'    => $this->config->get("{$driver}_auth_cid"), 
    672       'auth_pw'     => $this->config->get("{$driver}_auth_pw"), 
    673       'debug'       => (bool) $this->config->get("{$driver}_debug"), 
    674       'force_caps'  => (bool) $this->config->get("{$driver}_force_caps"), 
    675       'timeout'     => (int) $this->config->get("{$driver}_timeout"), 
    676       'skip_deleted' => (bool) $this->config->get('skip_deleted'), 
    677       'driver'      => $driver, 
    678     ); 
    679  
    680     if (!empty($_SESSION['storage_host'])) { 
    681       $options['host']     = $_SESSION['storage_host']; 
    682       $options['user']     = $_SESSION['username']; 
    683       $options['port']     = $_SESSION['storage_port']; 
    684       $options['ssl']      = $_SESSION['storage_ssl']; 
    685       $options['password'] = $this->decrypt($_SESSION['password']); 
    686     } 
    687  
    688     $options = $this->plugins->exec_hook("storage_init", $options); 
    689  
    690     // for backward compat. (deprecated, to be removed) 
    691     $options = $this->plugins->exec_hook("imap_init", $options); 
    692  
    693     $this->storage->set_options($options); 
    694     $this->set_storage_prop(); 
    695   } 
    696  
    697  
    698   /** 
    699    * Connect to the mail storage server with stored session data 
    700    * 
    701    * @return bool True on success, False on error 
    702    */ 
    703   public function storage_connect() 
    704   { 
    705     $storage = $this->get_storage(); 
    706  
    707     if ($_SESSION['storage_host'] && !$storage->is_connected()) { 
    708       $host = $_SESSION['storage_host']; 
    709       $user = $_SESSION['username']; 
    710       $port = $_SESSION['storage_port']; 
    711       $ssl  = $_SESSION['storage_ssl']; 
    712       $pass = $this->decrypt($_SESSION['password']); 
    713  
    714       if (!$storage->connect($host, $user, $pass, $port, $ssl)) { 
    715         if ($this->output) 
    716           $this->output->show_message($storage->get_error_code() == -1 ? 'storageerror' : 'sessionerror', 'error'); 
    717       } 
    718       else { 
    719         $this->set_storage_prop(); 
    720         return $storage->is_connected(); 
    721       } 
    722     } 
    723  
    724     return false; 
    725   } 
    726  
    727  
    728   /** 
    729334   * Create session object and start the session. 
    730335   */ 
     
    972577 
    973578  /** 
    974    * Set storage parameters. 
    975    * This must be done AFTER connecting to the server! 
    976    */ 
    977   private function set_storage_prop() 
    978   { 
    979     $storage = $this->get_storage(); 
    980  
    981     $storage->set_charset($this->config->get('default_charset', RCMAIL_CHARSET)); 
    982  
    983     if ($default_folders = $this->config->get('default_folders')) { 
    984       $storage->set_default_folders($default_folders); 
    985     } 
    986     if (isset($_SESSION['mbox'])) { 
    987       $storage->set_folder($_SESSION['mbox']); 
    988     } 
    989     if (isset($_SESSION['page'])) { 
    990       $storage->set_page($_SESSION['page']); 
    991     } 
    992   } 
    993  
    994  
    995   /** 
    996579   * Auto-select IMAP host based on the posted login information 
    997580   * 
     
    1038621 
    1039622  /** 
    1040    * Get localized text in the desired language 
    1041    * 
    1042    * @param mixed   $attrib  Named parameters array or label name 
    1043    * @param string  $domain  Label domain (plugin) name 
    1044    * 
    1045    * @return string Localized text 
    1046    */ 
    1047   public function gettext($attrib, $domain=null) 
    1048   { 
    1049     // load localization files if not done yet 
    1050     if (empty($this->texts)) 
    1051       $this->load_language(); 
    1052  
    1053     // extract attributes 
    1054     if (is_string($attrib)) 
    1055       $attrib = array('name' => $attrib); 
    1056  
    1057     $name = $attrib['name'] ? $attrib['name'] : ''; 
    1058  
    1059     // attrib contain text values: use them from now 
    1060     if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us'])) 
    1061         $this->texts[$name] = $setval; 
    1062  
    1063     // check for text with domain 
    1064     if ($domain && ($text = $this->texts[$domain.'.'.$name])) 
    1065       ; 
    1066     // text does not exist 
    1067     else if (!($text = $this->texts[$name])) { 
    1068       return "[$name]"; 
    1069     } 
    1070  
    1071     // replace vars in text 
    1072     if (is_array($attrib['vars'])) { 
    1073       foreach ($attrib['vars'] as $var_key => $var_value) 
    1074         $text = str_replace($var_key[0]!='$' ? '$'.$var_key : $var_key, $var_value, $text); 
    1075     } 
    1076  
    1077     // format output 
    1078     if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst']) 
    1079       return ucfirst($text); 
    1080     else if ($attrib['uppercase']) 
    1081       return mb_strtoupper($text); 
    1082     else if ($attrib['lowercase']) 
    1083       return mb_strtolower($text); 
    1084  
    1085     return strtr($text, array('\n' => "\n")); 
    1086   } 
    1087  
    1088  
    1089   /** 
    1090    * Check if the given text label exists 
    1091    * 
    1092    * @param string  $name       Label name 
    1093    * @param string  $domain     Label domain (plugin) name or '*' for all domains 
    1094    * @param string  $ref_domain Sets domain name if label is found 
    1095    * 
    1096    * @return boolean True if text exists (either in the current language or in en_US) 
    1097    */ 
    1098   public function text_exists($name, $domain = null, &$ref_domain = null) 
    1099   { 
    1100     // load localization files if not done yet 
    1101     if (empty($this->texts)) 
    1102       $this->load_language(); 
    1103  
    1104     if (isset($this->texts[$name])) { 
    1105         $ref_domain = ''; 
    1106         return true; 
    1107     } 
    1108  
    1109     // any of loaded domains (plugins) 
    1110     if ($domain == '*') { 
    1111       foreach ($this->plugins->loaded_plugins() as $domain) 
    1112         if (isset($this->texts[$domain.'.'.$name])) { 
    1113           $ref_domain = $domain; 
    1114           return true; 
    1115         } 
    1116     } 
    1117     // specified domain 
    1118     else if ($domain) { 
    1119       $ref_domain = $domain; 
    1120       return isset($this->texts[$domain.'.'.$name]); 
    1121     } 
    1122  
    1123     return false; 
    1124   } 
    1125  
    1126   /** 
    1127    * Load a localization package 
    1128    * 
    1129    * @param string Language ID 
    1130    */ 
    1131   public function load_language($lang = null, $add = array()) 
    1132   { 
    1133     $lang = $this->language_prop(($lang ? $lang : $_SESSION['language'])); 
    1134  
    1135     // load localized texts 
    1136     if (empty($this->texts) || $lang != $_SESSION['language']) { 
    1137       $this->texts = array(); 
    1138  
    1139       // handle empty lines after closing PHP tag in localization files 
    1140       ob_start(); 
    1141  
    1142       // get english labels (these should be complete) 
    1143       @include(INSTALL_PATH . 'program/localization/en_US/labels.inc'); 
    1144       @include(INSTALL_PATH . 'program/localization/en_US/messages.inc'); 
    1145  
    1146       if (is_array($labels)) 
    1147         $this->texts = $labels; 
    1148       if (is_array($messages)) 
    1149         $this->texts = array_merge($this->texts, $messages); 
    1150  
    1151       // include user language files 
    1152       if ($lang != 'en' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) { 
    1153         include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc'); 
    1154         include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc'); 
    1155  
    1156         if (is_array($labels)) 
    1157           $this->texts = array_merge($this->texts, $labels); 
    1158         if (is_array($messages)) 
    1159           $this->texts = array_merge($this->texts, $messages); 
    1160       } 
    1161  
    1162       ob_end_clean(); 
    1163  
    1164       $_SESSION['language'] = $lang; 
    1165     } 
    1166  
    1167     // append additional texts (from plugin) 
    1168     if (is_array($add) && !empty($add)) 
    1169       $this->texts += $add; 
    1170   } 
    1171  
    1172  
    1173   /** 
    1174    * Read directory program/localization and return a list of available languages 
    1175    * 
    1176    * @return array List of available localizations 
    1177    */ 
    1178   public function list_languages() 
    1179   { 
    1180     static $sa_languages = array(); 
    1181  
    1182     if (!sizeof($sa_languages)) { 
    1183       @include(INSTALL_PATH . 'program/localization/index.inc'); 
    1184  
    1185       if ($dh = @opendir(INSTALL_PATH . 'program/localization')) { 
    1186         while (($name = readdir($dh)) !== false) { 
    1187           if ($name[0] == '.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name)) 
    1188             continue; 
    1189  
    1190           if ($label = $rcube_languages[$name]) 
    1191             $sa_languages[$name] = $label; 
    1192         } 
    1193         closedir($dh); 
    1194       } 
    1195     } 
    1196  
    1197     return $sa_languages; 
    1198   } 
    1199  
    1200  
    1201   /** 
    1202623   * Destroy session data and remove cookie 
    1203624   */ 
     
    1239660      $this->user->save_prefs(unserialize($_SESSION['preferences'])); 
    1240661    } 
    1241   } 
    1242  
    1243  
    1244   /** 
    1245    * Function to be executed in script shutdown 
    1246    * Registered with register_shutdown_function() 
    1247    */ 
    1248   public function shutdown() 
    1249   { 
    1250     foreach ($this->shutdown_functions as $function) 
    1251       call_user_func($function); 
    1252  
    1253     if (is_object($this->smtp)) 
    1254       $this->smtp->disconnect(); 
    1255  
    1256     foreach ($this->address_books as $book) { 
    1257       if (is_object($book) && is_a($book, 'rcube_addressbook')) 
    1258         $book->close(); 
    1259     } 
    1260  
    1261     foreach ($this->caches as $cache) { 
    1262         if (is_object($cache)) 
    1263             $cache->close(); 
    1264     } 
    1265  
    1266     if (is_object($this->storage)) 
    1267       $this->storage->close(); 
    1268  
    1269     // before closing the database connection, write session data 
    1270     if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) { 
    1271       session_write_close(); 
    1272     } 
    1273  
    1274     // write performance stats to logs/console 
    1275     if ($this->config->get('devel_mode')) { 
    1276       if (function_exists('memory_get_usage')) 
    1277         $mem = rcube_ui::show_bytes(memory_get_usage()); 
    1278       if (function_exists('memory_get_peak_usage')) 
    1279         $mem .= '/'.rcube_ui::show_bytes(memory_get_peak_usage()); 
    1280  
    1281       $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : ''); 
    1282       if (defined('RCMAIL_START')) 
    1283         self::print_timer(RCMAIL_START, $log); 
    1284       else 
    1285         self::console($log); 
    1286     } 
    1287   } 
    1288  
    1289  
    1290   /** 
    1291    * Registers shutdown function to be executed on shutdown. 
    1292    * The functions will be executed before destroying any 
    1293    * objects like smtp, imap, session, etc. 
    1294    * 
    1295    * @param callback Function callback 
    1296    */ 
    1297   public function add_shutdown_function($function) 
    1298   { 
    1299     $this->shutdown_functions[] = $function; 
    1300662  } 
    1301663 
     
    1350712  } 
    1351713 
    1352  
    1353   /** 
    1354    * Encrypt using 3DES 
    1355    * 
    1356    * @param string $clear clear text input 
    1357    * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key' 
    1358    * @param boolean $base64 whether or not to base64_encode() the result before returning 
    1359    * 
    1360    * @return string encrypted text 
    1361    */ 
    1362   public function encrypt($clear, $key = 'des_key', $base64 = true) 
    1363   { 
    1364     if (!$clear) 
    1365       return ''; 
    1366     /*- 
    1367      * Add a single canary byte to the end of the clear text, which 
    1368      * will help find out how much of padding will need to be removed 
    1369      * upon decryption; see http://php.net/mcrypt_generic#68082 
    1370      */ 
    1371     $clear = pack("a*H2", $clear, "80"); 
    1372  
    1373     if (function_exists('mcrypt_module_open') && 
    1374         ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) 
    1375     { 
    1376       $iv = $this->create_iv(mcrypt_enc_get_iv_size($td)); 
    1377       mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv); 
    1378       $cipher = $iv . mcrypt_generic($td, $clear); 
    1379       mcrypt_generic_deinit($td); 
    1380       mcrypt_module_close($td); 
    1381     } 
    1382     else { 
    1383       @include_once 'des.inc'; 
    1384  
    1385       if (function_exists('des')) { 
    1386         $des_iv_size = 8; 
    1387         $iv = $this->create_iv($des_iv_size); 
    1388         $cipher = $iv . des($this->config->get_crypto_key($key), $clear, 1, 1, $iv); 
    1389       } 
    1390       else { 
    1391         self::raise_error(array( 
    1392           'code' => 500, 'type' => 'php', 
    1393           'file' => __FILE__, 'line' => __LINE__, 
    1394           'message' => "Could not perform encryption; make sure Mcrypt is installed or lib/des.inc is available" 
    1395         ), true, true); 
    1396       } 
    1397     } 
    1398  
    1399     return $base64 ? base64_encode($cipher) : $cipher; 
    1400   } 
    1401  
    1402   /** 
    1403    * Decrypt 3DES-encrypted string 
    1404    * 
    1405    * @param string $cipher encrypted text 
    1406    * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key' 
    1407    * @param boolean $base64 whether or not input is base64-encoded 
    1408    * 
    1409    * @return string decrypted text 
    1410    */ 
    1411   public function decrypt($cipher, $key = 'des_key', $base64 = true) 
    1412   { 
    1413     if (!$cipher) 
    1414       return ''; 
    1415  
    1416     $cipher = $base64 ? base64_decode($cipher) : $cipher; 
    1417  
    1418     if (function_exists('mcrypt_module_open') && 
    1419         ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) 
    1420     { 
    1421       $iv_size = mcrypt_enc_get_iv_size($td); 
    1422       $iv = substr($cipher, 0, $iv_size); 
    1423  
    1424       // session corruption? (#1485970) 
    1425       if (strlen($iv) < $iv_size) 
    1426         return ''; 
    1427  
    1428       $cipher = substr($cipher, $iv_size); 
    1429       mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv); 
    1430       $clear = mdecrypt_generic($td, $cipher); 
    1431       mcrypt_generic_deinit($td); 
    1432       mcrypt_module_close($td); 
    1433     } 
    1434     else { 
    1435       @include_once 'des.inc'; 
    1436  
    1437       if (function_exists('des')) { 
    1438         $des_iv_size = 8; 
    1439         $iv = substr($cipher, 0, $des_iv_size); 
    1440         $cipher = substr($cipher, $des_iv_size); 
    1441         $clear = des($this->config->get_crypto_key($key), $cipher, 0, 1, $iv); 
    1442       } 
    1443       else { 
    1444         self::raise_error(array( 
    1445           'code' => 500, 'type' => 'php', 
    1446           'file' => __FILE__, 'line' => __LINE__, 
    1447           'message' => "Could not perform decryption; make sure Mcrypt is installed or lib/des.inc is available" 
    1448         ), true, true); 
    1449       } 
    1450     } 
    1451  
    1452     /*- 
    1453      * Trim PHP's padding and the canary byte; see note in 
    1454      * rcmail::encrypt() and http://php.net/mcrypt_generic#68082 
    1455      */ 
    1456     $clear = substr(rtrim($clear, "\0"), 0, -1); 
    1457  
    1458     return $clear; 
    1459   } 
    1460  
    1461   /** 
    1462    * Generates encryption initialization vector (IV) 
    1463    * 
    1464    * @param int Vector size 
    1465    * @return string Vector string 
    1466    */ 
    1467   private function create_iv($size) 
    1468   { 
    1469     // mcrypt_create_iv() can be slow when system lacks entrophy 
    1470     // we'll generate IV vector manually 
    1471     $iv = ''; 
    1472     for ($i = 0; $i < $size; $i++) 
    1473         $iv .= chr(mt_rand(0, 255)); 
    1474     return $iv; 
    1475   } 
    1476714 
    1477715  /** 
     
    1500738    } 
    1501739    return $url; 
    1502   } 
    1503  
    1504  
    1505   /** 
    1506    * Use imagemagick or GD lib to read image properties 
    1507    * 
    1508    * @param string Absolute file path 
    1509    * @return mixed Hash array with image props like type, width, height or False on error 
    1510    */ 
    1511   public static function imageprops($filepath) 
    1512   { 
    1513     $rcmail = rcmail::get_instance(); 
    1514     if ($cmd = $rcmail->config->get('im_identify_path', false)) { 
    1515       list(, $type, $size) = explode(' ', strtolower(rcmail::exec($cmd. ' 2>/dev/null {in}', array('in' => $filepath)))); 
    1516       if ($size) 
    1517         list($width, $height) = explode('x', $size); 
    1518     } 
    1519     else if (function_exists('getimagesize')) { 
    1520       $imsize = @getimagesize($filepath); 
    1521       $width = $imsize[0]; 
    1522       $height = $imsize[1]; 
    1523       $type = preg_replace('!image/!', '', $imsize['mime']); 
    1524     } 
    1525  
    1526     return $type ? array('type' => $type, 'width' => $width, 'height' => $height) : false; 
    1527   } 
    1528  
    1529  
    1530   /** 
    1531    * Convert an image to a given size and type using imagemagick (ensures input is an image) 
    1532    * 
    1533    * @param $p['in']  Input filename (mandatory) 
    1534    * @param $p['out'] Output filename (mandatory) 
    1535    * @param $p['size']  Width x height of resulting image, e.g. "160x60" 
    1536    * @param $p['type']  Output file type, e.g. "jpg" 
    1537    * @param $p['-opts'] Custom command line options to ImageMagick convert 
    1538    * @return Success of convert as true/false 
    1539    */ 
    1540   public static function imageconvert($p) 
    1541   { 
    1542     $result = false; 
    1543     $rcmail = rcmail::get_instance(); 
    1544     $convert  = $rcmail->config->get('im_convert_path', false); 
    1545     $identify = $rcmail->config->get('im_identify_path', false); 
    1546  
    1547     // imagemagick is required for this 
    1548     if (!$convert) 
    1549         return false; 
    1550  
    1551     if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false)))) 
    1552       list(, $type) = explode(' ', strtolower(rcmail::exec($identify . ' 2>/dev/null {in}', $p))); # for things like eps 
    1553  
    1554     $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps")); 
    1555     $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75); 
    1556     $p['-opts'] = array('-resize' => $p['size'].'>') + (array)$p['-opts']; 
    1557  
    1558     if (in_array($type, explode(',', $p['types']))) # Valid type? 
    1559       $result = rcmail::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === ""; 
    1560  
    1561     return $result; 
    1562   } 
    1563  
    1564  
    1565   /** 
    1566    * Construct shell command, execute it and return output as string. 
    1567    * Keywords {keyword} are replaced with arguments 
    1568    * 
    1569    * @param $cmd Format string with {keywords} to be replaced 
    1570    * @param $values (zero, one or more arrays can be passed) 
    1571    * @return output of command. shell errors not detectable 
    1572    */ 
    1573   public static function exec(/* $cmd, $values1 = array(), ... */) 
    1574   { 
    1575     $args = func_get_args(); 
    1576     $cmd = array_shift($args); 
    1577     $values = $replacements = array(); 
    1578  
    1579     // merge values into one array 
    1580     foreach ($args as $arg) 
    1581       $values += (array)$arg; 
    1582  
    1583     preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER); 
    1584     foreach ($matches as $tags) { 
    1585       list(, $tag, $option, $key) = $tags; 
    1586       $parts = array(); 
    1587  
    1588       if ($option) { 
    1589         foreach ((array)$values["-$key"] as $key => $value) { 
    1590           if ($value === true || $value === false || $value === null) 
    1591             $parts[] = $value ? $key : ""; 
    1592           else foreach ((array)$value as $val) 
    1593             $parts[] = "$key " . escapeshellarg($val); 
    1594         } 
    1595       } 
    1596       else { 
    1597         foreach ((array)$values[$key] as $value) 
    1598           $parts[] = escapeshellarg($value); 
    1599       } 
    1600  
    1601       $replacements[$tag] = join(" ", $parts); 
    1602     } 
    1603  
    1604     // use strtr behaviour of going through source string once 
    1605     $cmd = strtr($cmd, $replacements); 
    1606  
    1607     return (string)shell_exec($cmd); 
    1608740  } 
    1609741 
     
    19611093 
    19621094    /** 
    1963      * Replaces hostname variables. 
    1964      * 
    1965      * @param string $name Hostname 
    1966      * @param string $host Optional IMAP hostname 
    1967      * 
    1968      * @return string Hostname 
    1969      */ 
    1970     public static function parse_host($name, $host = '') 
    1971     { 
    1972         // %n - host 
    1973         $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); 
    1974         // %d - domain name without first part, e.g. %n=mail.domain.tld, %d=domain.tld 
    1975         $d = preg_replace('/^[^\.]+\./', '', $n); 
    1976         // %h - IMAP host 
    1977         $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host; 
    1978         // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld 
    1979         $z = preg_replace('/^[^\.]+\./', '', $h); 
    1980         // %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided 
    1981         if (strpos($name, '%s') !== false) { 
    1982             $user_email = rcube_ui::get_input_value('_user', rcube_ui::INPUT_POST); 
    1983             $user_email = rcube_idn_convert($user_email, true); 
    1984             $matches    = preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s); 
    1985             if ($matches < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false) { 
    1986                 return false; 
    1987             } 
    1988         } 
    1989  
    1990         $name = str_replace(array('%n', '%d', '%h', '%z', '%s'), array($n, $d, $h, $z, $s[2]), $name); 
    1991         return $name; 
    1992     } 
    1993  
    1994  
    1995     /** 
    19961095     * E-mail address validation. 
    19971096     * 
     
    20821181 
    20831182    /** 
    2084      * Print or write debug messages 
    2085      * 
    2086      * @param mixed Debug message or data 
    2087      */ 
    2088     public static function console() 
    2089     { 
    2090         $args = func_get_args(); 
    2091  
    2092         if (class_exists('rcmail', false)) { 
    2093             $rcmail = rcmail::get_instance(); 
    2094             if (is_object($rcmail->plugins)) { 
    2095                 $plugin = $rcmail->plugins->exec_hook('console', array('args' => $args)); 
    2096                 if ($plugin['abort']) { 
    2097                     return; 
    2098                 } 
    2099                $args = $plugin['args']; 
    2100             } 
    2101         } 
    2102  
    2103         $msg = array(); 
    2104         foreach ($args as $arg) { 
    2105             $msg[] = !is_string($arg) ? var_export($arg, true) : $arg; 
    2106         } 
    2107  
    2108         self::write_log('console', join(";\n", $msg)); 
    2109     } 
    2110  
    2111  
    2112     /** 
    2113      * Append a line to a logfile in the logs directory. 
    2114      * Date will be added automatically to the line. 
    2115      * 
    2116      * @param $name name of log file 
    2117      * @param line Line to append 
    2118      */ 
    2119     public static function write_log($name, $line) 
    2120     { 
    2121         global $RCMAIL; 
    2122  
    2123         if (!is_string($line)) { 
    2124             $line = var_export($line, true); 
    2125         } 
    2126  
    2127         $date_format = $RCMAIL ? $RCMAIL->config->get('log_date_format') : null; 
    2128         $log_driver  = $RCMAIL ? $RCMAIL->config->get('log_driver') : null; 
    2129  
    2130         if (empty($date_format)) { 
    2131             $date_format = 'd-M-Y H:i:s O'; 
    2132         } 
    2133  
    2134         $date = date($date_format); 
    2135  
    2136         // trigger logging hook 
    2137         if (is_object($RCMAIL) && is_object($RCMAIL->plugins)) { 
    2138             $log  = $RCMAIL->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line)); 
    2139             $name = $log['name']; 
    2140             $line = $log['line']; 
    2141             $date = $log['date']; 
    2142             if ($log['abort']) 
    2143                 return true; 
    2144         } 
    2145  
    2146         if ($log_driver == 'syslog') { 
    2147             $prio = $name == 'errors' ? LOG_ERR : LOG_INFO; 
    2148             syslog($prio, $line); 
    2149             return true; 
    2150         } 
    2151  
    2152         // log_driver == 'file' is assumed here 
    2153  
    2154         $line = sprintf("[%s]: %s\n", $date, $line); 
    2155         $log_dir  = $RCMAIL ? $RCMAIL->config->get('log_dir') : null; 
    2156  
    2157         if (empty($log_dir)) { 
    2158             $log_dir = INSTALL_PATH . 'logs'; 
    2159         } 
    2160  
    2161         // try to open specific log file for writing 
    2162         $logfile = $log_dir.'/'.$name; 
    2163  
    2164         if ($fp = @fopen($logfile, 'a')) { 
    2165             fwrite($fp, $line); 
    2166             fflush($fp); 
    2167             fclose($fp); 
    2168             return true; 
    2169         } 
    2170  
    2171         trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING); 
    2172         return false; 
    2173     } 
    2174  
    2175  
    2176     /** 
    2177      * Throw system error (and show error page). 
    2178      * 
    2179      * @param array Named parameters 
    2180      *      - code:    Error code (required) 
    2181      *      - type:    Error type [php|db|imap|javascript] (required) 
    2182      *      - message: Error message 
    2183      *      - file:    File where error occured 
    2184      *      - line:    Line where error occured 
    2185      * @param boolean True to log the error 
    2186      * @param boolean Terminate script execution 
    2187      */ 
    2188     public static function raise_error($arg = array(), $log = false, $terminate = false) 
    2189     { 
    2190         // installer 
    2191         if (class_exists('rcube_install', false)) { 
    2192             $rci = rcube_install::get_instance(); 
    2193             $rci->raise_error($arg); 
    2194             return; 
    2195         } 
    2196  
    2197         if ($log && $arg['type'] && $arg['message']) { 
    2198             self::log_bug($arg); 
    2199         } 
    2200  
    2201         // display error page and terminate script 
    2202         if ($terminate) { 
    2203             rcube_ui::raise_error($arg['code'], $arg['message']); 
    2204         } 
    2205     } 
    2206  
    2207  
    2208     /** 
    2209      * Report error according to configured debug_level 
    2210      * 
    2211      * @param array Named parameters 
    2212      * @see self::raise_error() 
    2213      */ 
    2214     public static function log_bug($arg_arr) 
    2215     { 
    2216         $rcmail  = rcmail::get_instance(); 
    2217         $program = strtoupper($arg_arr['type']); 
    2218         $level   = $rcmail->config->get('debug_level'); 
    2219  
    2220         // disable errors for ajax requests, write to log instead (#1487831) 
    2221         if (($level & 4) && !empty($_REQUEST['_remote'])) { 
    2222             $level = ($level ^ 4) | 1; 
    2223         } 
    2224  
    2225         // write error to local log file 
    2226         if ($level & 1) { 
    2227             if ($_SERVER['REQUEST_METHOD'] == 'POST') { 
    2228                 $post_query = '?_task='.urlencode($_POST['_task']).'&_action='.urlencode($_POST['_action']); 
    2229             } 
    2230             else { 
    2231                 $post_query = ''; 
    2232             } 
    2233  
    2234             $log_entry = sprintf("%s Error: %s%s (%s %s)", 
    2235                 $program, 
    2236                 $arg_arr['message'], 
    2237                 $arg_arr['file'] ? sprintf(' in %s on line %d', $arg_arr['file'], $arg_arr['line']) : '', 
    2238                 $_SERVER['REQUEST_METHOD'], 
    2239                 $_SERVER['REQUEST_URI'] . $post_query); 
    2240  
    2241             if (!self::write_log('errors', $log_entry)) { 
    2242                 // send error to PHPs error handler if write_log didn't succeed 
    2243                 trigger_error($arg_arr['message']); 
    2244             } 
    2245         } 
    2246  
    2247         // report the bug to the global bug reporting system 
    2248         if ($level & 2) { 
    2249             // TODO: Send error via HTTP 
    2250         } 
    2251  
    2252         // show error if debug_mode is on 
    2253         if ($level & 4) { 
    2254             print "<b>$program Error"; 
    2255  
    2256             if (!empty($arg_arr['file']) && !empty($arg_arr['line'])) { 
    2257                 print " in $arg_arr[file] ($arg_arr[line])"; 
    2258             } 
    2259  
    2260             print ':</b>&nbsp;'; 
    2261             print nl2br($arg_arr['message']); 
    2262             print '<br />'; 
    2263             flush(); 
    2264         } 
    2265     } 
    2266  
    2267  
    2268     /** 
    22691183     * Write login data (name, ID, IP address) to the 'userlogins' log file. 
    22701184     */ 
     
    22851199            sprintf('Successful login for %s (ID: %d) from %s in session %s', 
    22861200                $user_name, $user_id, self::remote_ip(), session_id())); 
    2287     } 
    2288  
    2289  
    2290     /** 
    2291      * Returns remote IP address and forwarded addresses if found 
    2292      * 
    2293      * @return string Remote IP address(es) 
    2294      */ 
    2295     public static function remote_ip() 
    2296     { 
    2297         $address = $_SERVER['REMOTE_ADDR']; 
    2298  
    2299         // append the NGINX X-Real-IP header, if set 
    2300         if (!empty($_SERVER['HTTP_X_REAL_IP'])) { 
    2301             $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP']; 
    2302         } 
    2303         // append the X-Forwarded-For header, if set 
    2304         if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 
    2305             $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR']; 
    2306         } 
    2307  
    2308         if (!empty($remote_ip)) { 
    2309             $address .= '(' . implode(',', $remote_ip) . ')'; 
    2310         } 
    2311  
    2312         return $address; 
    23131201    } 
    23141202 
     
    23281216 
    23291217    /** 
    2330      * Returns current time (with microseconds). 
    2331      * 
    2332      * @return float Current time in seconds since the Unix 
    2333      */ 
    2334     public static function timer() 
    2335     { 
    2336         return microtime(true); 
    2337     } 
    2338  
    2339  
    2340     /** 
    2341      * Logs time difference according to provided timer 
    2342      * 
    2343      * @param float  $timer  Timer (self::timer() result) 
    2344      * @param string $label  Log line prefix 
    2345      * @param string $dest   Log file name 
    2346      * 
    2347      * @see self::timer() 
    2348      */ 
    2349     public static function print_timer($timer, $label = 'Timer', $dest = 'console') 
    2350     { 
    2351         static $print_count = 0; 
    2352  
    2353         $print_count++; 
    2354         $now  = self::timer(); 
    2355         $diff = $now - $timer; 
    2356  
    2357         if (empty($label)) { 
    2358             $label = 'Timer '.$print_count; 
    2359         } 
    2360  
    2361         self::write_log($dest, sprintf("%s: %0.4f sec", $label, $diff)); 
    2362     } 
    2363  
    2364  
    2365     /** 
    23661218     * Garbage collector function for temp files. 
    23671219     * Remove temp files older than two days 
     
    24121264    } 
    24131265 
    2414  
    2415     /** 
    2416      * Getter for logged user ID. 
    2417      * 
    2418      * @return mixed User identifier 
    2419      */ 
    2420     public function get_user_id() 
    2421     { 
    2422         if (is_object($this->user)) { 
    2423             return $this->user->ID; 
    2424         } 
    2425     } 
    2426  
    2427  
    2428     /** 
    2429      * Getter for logged user name. 
    2430      * 
    2431      * @return string User name 
    2432      */ 
    2433     public function get_user_name() 
    2434     { 
    2435         if (is_object($this->user)) { 
    2436             return $this->user->get_username(); 
    2437         } 
    2438     } 
    24391266} 
Note: See TracChangeset for help on using the changeset viewer.