From: Jérémy Bobbio Date: Sat, 18 Jun 2011 15:02:10 +0000 (+0200) Subject: Imported Upstream version 0.2~alpha X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=48e8459231a1efa3e97284d07a328776a5b7485b;p=roundcube.git Imported Upstream version 0.2~alpha --- diff --git a/._INSTALL b/._INSTALL new file mode 100644 index 0000000..9293550 Binary files /dev/null and b/._INSTALL differ diff --git a/._README b/._README new file mode 100644 index 0000000..7cc650c Binary files /dev/null and b/._README differ diff --git a/._UPGRADING b/._UPGRADING new file mode 100644 index 0000000..64a3886 Binary files /dev/null and b/._UPGRADING differ diff --git a/CHANGELOG b/CHANGELOG index 8093ccc..d0fa0e4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,57 @@ CHANGELOG RoundCube Webmail --------------------------- +- Added option to disable autocompletion from selected LDAP address books (#1484922) +- TLS support in LDAP connections: 'use_tls' property (#1485104) +- Fixed removing messages from search set after deleting them (#1485106) +- imap.inc: Fixed iil_C_FetchStructureString() to handle many + literal strings in response (#1484969) +- Support for subfolders in default/protected folders (#1484665) +- Disallowed delimiter in folder name (#1484803) +- Support " and \ in folder names +- Escape \ in login (#1484614) +- Better HTML sanitization with the DOM-based washtml script (#1484701) +- Fixed sorting of folders with non-ascii characters +- Fixed Mysql DDL for default identities creation (#1485070) +- In Preferences added possibility to configure 'read_when_deleted', + 'mdn_requests', 'flag_for_deletion' options +- Made IMAP auth type configurable (#1483825) +- Fixed empty values with FROM_UNIXTIME() in rcube_mdb2 (#1485055) +- Fixed attachment list on IE 6/7 (#1484807) +- Fixed JavaScript in compose.html that shows cc/bcc fields if populated +- Make password input fields of type password in installer (#1484886) +- Don't attempt to delete cache entries if enable_caching is FALSE (#1485051) +- Optimized messages sorting on servers without sort capability (#1485049) +- Corrected message headers decoding when charset isn't specified and improved + support for native languages (#1485050, #1485048) +- Expanded LDAP configuration options to support LDAP server writes. +- Installer: encode special characters in DB username/password (#1485042) +- Fixed management of folders with national characters in names (#1485036, #1485001) +- Fixed identities saving when using MDB2 pgsql driver (#1485032) +- Fixed BCC header reset (#1484997) +- Improved messages list performance - patch from Justin Heesemann +- Append skin_path to images location only when it starts with '/' sign (#1484859) +- Fix IMAP response in message body when message has no body (#1484964) +- Fixed non-RFC dates formatting (#1484901) +- Fixed typo in set_charset() (#1484991) +- Decode entities when inserting HTML signature to plain text message (#1484990) +- HTML editing is now working with PHP5 updates and TinyMCE v3.0.6 +- Fixed signature loading on Windows (#1484545) +- Added language support to HTML editing (#1484862) +- Fixed remove signature when replying (#1333167) +- Fixed problem with line with a space at the end (#1484916) +- Fixed tag filtering (#1484391) +- Fixed tag filtering (#1484403) +- Added sections (fieldset+label) in Settings interface +- Mark as read in one action with message preview (#1484972) +- Deleted redundant quota reads (#1484972) +- Added options for empty trash and expunge inbox on logout (#1483863) +- Removed lines wrapping when displaying message +- Fixed month localization +- Changed codebase to PHP5 with autoloader + +RELEASE 0.1.1 + - Clear selection when selecting single item (#1484942) - Remove hard-coded image size in skin templates (#1484893) - Database schema improvements (dropped unnecessary indexes) diff --git a/INSTALL b/INSTALL index 2b8fb2e..e2f9a4e 100644 --- a/INSTALL +++ b/INSTALL @@ -11,7 +11,7 @@ REQUIREMENTS * The Apache or Lighttpd Webserver * .htaccess support allowing overrides for DirectoryIndex -* PHP Version 4.3.1 or greater including +* PHP Version 5.2 or greater including - PCRE (perl compatible regular expression) - Libiconv - Multibyte String (mbstring) diff --git a/README b/README index 7aae054..e23c494 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ RoundCube Webmail (http://roundcube.net) - +================= Introduction: ------------- @@ -43,6 +43,9 @@ records. If you have 'auto_create_user' set to FALSE only IMAP logins which already have a corresponding entry in the user's table (username and hostname) will be allowed. +Read more at http://trac.roundcube.net/wiki/Howto_Config +and http://trac.roundcube.net/wiki/Dev_Docs + Contact: -------- diff --git a/SQL/mysql.initial.sql b/SQL/mysql.initial.sql index ae195e4..fadc072 100644 --- a/SQL/mysql.initial.sql +++ b/SQL/mysql.initial.sql @@ -50,12 +50,12 @@ CREATE TABLE `identities` ( `user_id` int(10) unsigned NOT NULL default '0', `del` tinyint(1) NOT NULL default '0', `standard` tinyint(1) NOT NULL default '0', - `name` varchar(128) NOT NULL default '', + `name` varchar(128) NOT NULL, `organization` varchar(128) NOT NULL default '', - `email` varchar(128) NOT NULL default '', + `email` varchar(128) NOT NULL, `reply-to` varchar(128) NOT NULL default '', `bcc` varchar(128) NOT NULL default '', - `signature` text NOT NULL, + `signature` text NOT NULL default '', `html_signature` tinyint(1) NOT NULL default '0', PRIMARY KEY (`identity_id`), KEY `user_id` (`user_id`) @@ -91,7 +91,9 @@ CREATE TABLE `users` ( `last_login` datetime NOT NULL default '0000-00-00 00:00:00', `language` varchar(5) NOT NULL default 'en', `preferences` text, - PRIMARY KEY (`user_id`) + PRIMARY KEY (`user_id`), + INDEX `username_index` (`username`), + INDEX `alias_index` (`alias`) ); -- -------------------------------------------------------- diff --git a/SQL/mysql.update.sql b/SQL/mysql.update.sql index 11e744c..2a9603f 100644 --- a/SQL/mysql.update.sql +++ b/SQL/mysql.update.sql @@ -5,7 +5,7 @@ TRUNCATE TABLE `messages`; ALTER TABLE `messages` DROP INDEX `idx`, - DROP INDEX `uid` + DROP INDEX `uid`; ALTER TABLE `cache` DROP INDEX `cache_key`, @@ -15,3 +15,13 @@ ALTER TABLE `cache` ALTER TABLE `users` ADD INDEX `username_index` (`username`), ADD INDEX `alias_index` (`alias`); + +-- Updates from version 0.1.1 + +ALTER TABLE `identities` + MODIFY `signature` text NOT NULL DEFAULT '', + MODIFY `bcc` varchar(128) NOT NULL DEFAULT '', + MODIFY `reply-to` varchar(128) NOT NULL DEFAULT '', + MODIFY `organization` varchar(128) NOT NULL DEFAULT '', + MODIFY `name` varchar(128) NOT NULL, + MODIFY `email` varchar(128) NOT NULL; diff --git a/SQL/mysql5.initial.sql b/SQL/mysql5.initial.sql index 881344b..546eecd 100644 --- a/SQL/mysql5.initial.sql +++ b/SQL/mysql5.initial.sql @@ -107,11 +107,11 @@ CREATE TABLE `identities` ( `del` tinyint(1) NOT NULL DEFAULT '0', `standard` tinyint(1) NOT NULL DEFAULT '0', `name` varchar(128) NOT NULL, - `organization` varchar(128) NOT NULL, + `organization` varchar(128) NOT NULL DEFAULT '', `email` varchar(128) NOT NULL, - `reply-to` varchar(128) NOT NULL, - `bcc` varchar(128) NOT NULL, - `signature` text NOT NULL, + `reply-to` varchar(128) NOT NULL DEFAULT '', + `bcc` varchar(128) NOT NULL DEFAULT '', + `signature` text NOT NULL DEFAULT '', `html_signature` tinyint(1) NOT NULL DEFAULT '0', `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY(`identity_id`), diff --git a/SQL/postgres.initial.sql b/SQL/postgres.initial.sql index ff239cb..05c6192 100644 --- a/SQL/postgres.initial.sql +++ b/SQL/postgres.initial.sql @@ -25,7 +25,10 @@ CREATE TABLE users ( preferences text DEFAULT ''::text NOT NULL ); +CREATE INDEX users_username_id_idx ON users (username); +CREATE INDEX users_alias_id_idx ON users (alias); + -- -- Table "session" -- Name: session; Type: TABLE; Schema: public; Owner: postgres diff --git a/SQL/postgres.update.sql b/SQL/postgres.update.sql index ff1ce12..e0afa61 100644 --- a/SQL/postgres.update.sql +++ b/SQL/postgres.update.sql @@ -5,6 +5,9 @@ CREATE INDEX cache_user_id_idx ON cache (user_id, cache_key); CREATE INDEX contacts_user_id_idx ON contacts (user_id); CREATE INDEX identities_user_id_idx ON identities (user_id); +CREATE INDEX users_username_id_idx ON users (username); +CREATE INDEX users_alias_id_idx ON users (alias); + -- added ON DELETE/UPDATE actions ALTER TABLE messages DROP CONSTRAINT messages_user_id_fkey; ALTER TABLE messages ADD FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/SQL/sqlite.initial.sql b/SQL/sqlite.initial.sql index 041696b..6adcf4d 100644 --- a/SQL/sqlite.initial.sql +++ b/SQL/sqlite.initial.sql @@ -80,6 +80,9 @@ CREATE TABLE users ( preferences text NOT NULL default '' ); +CREATE INDEX ix_users_username ON users(username); +CREATE INDEX ix_users_alias ON users(alias); + -- -------------------------------------------------------- -- diff --git a/SQL/sqlite.update.sql b/SQL/sqlite.update.sql index f609a36..047fe67 100644 --- a/SQL/sqlite.update.sql +++ b/SQL/sqlite.update.sql @@ -22,3 +22,6 @@ CREATE TABLE messages ( ); CREATE INDEX ix_messages_user_cache_uid ON messages(user_id,cache_key,uid); + +CREATE INDEX ix_users_username ON users(username); +CREATE INDEX ix_users_alias ON users(alias); diff --git a/UPGRADING b/UPGRADING index 9b5ac45..996b4f2 100644 --- a/UPGRADING +++ b/UPGRADING @@ -1,9 +1,25 @@ UPDATE instructions =================== -Follow these instructions if upgrading from a previous version +First you should remove all subfolders from /program/localization/ +because most language codes have changed in 0.2-alpha. This way you +can make sure that no old localization files remain on your disk. + +Then follow these instructions if upgrading from a previous version of RoundCube Webmail. +from version 0.1.1 +---------------------------------------- +* replace index.php +* replace all files in folder /bin/ +* replace all files in folder /program/ +* replace all files in folder /skins/default/ +* run all commands in SQL/[yourdbtype].update.sql + below the line "-- Updates from version 0.1.1" +* check the config/main.inc.php.dist for new configuration + options and add them to your config + + from version 0.1-stable ---------------------------------------- * replace index.php @@ -11,6 +27,8 @@ from version 0.1-stable * replace all files in folder /program/ * replace all files in folder /skins/default/ * run all commands in SQL/[yourdbtype].update.sql +* check the config/main.inc.php.dist for new configuration options + and add them to your config from version 0.1-rc2 @@ -28,7 +46,6 @@ from version 0.1-rc1 * replace all files in folder /bin/ * replace all files in folder /program/ * replace all files in folder /skins/default/ -* run all commands in SQL/[yourdbtype].update.sql * If you have LDAP servers configured you should re-configure the config entries using the template given in /config/main.inc.php.dist @@ -39,7 +56,8 @@ from version 0.1-beta2 * replace all files in folder /bin/ * replace all files in folder /program/ * replace all files in folder /skins/default/ -* re-initalize the database with [yourdbtype].initial.sql +* run all commands in SQL/[yourdbtype].update.sql or + re-initalize the database with [yourdbtype].initial.sql * add these lines to /config/main.inc.php $rcmail_config['draft_autosave'] = 300; $rcmail_config['date_today'] = 'H:i'; @@ -53,7 +71,8 @@ form version 0.1-beta * replace all files in folder /bin/ * replace all files in folder /program/ * replace all files in folder /skins/default/ -* re-initalize the database with [yourdbtype].initial.sql +* run all commands in SQL/[yourdbtype].update.sql or + re-initalize the database with [yourdbtype].initial.sql * add this line to /config/db.inc.php $rcmail_config['db_persistent'] = false; * add these lines to /config/main.inc.php diff --git a/bin/html2text.php b/bin/html2text.php index 7f74ac6..0f0e6ae 100644 --- a/bin/html2text.php +++ b/bin/html2text.php @@ -1,21 +1,11 @@ get_text(); - -$phpver = explode('.', phpversion()); -$vernum = $phpver[0] . $phpver[1] . $phpver[2]; - -# html_entity_decode doesn't handle UTF character sets in PHP 4.x - -if (($vernum >= 500) && function_exists('html_entity_decode')) - print html_entity_decode($plaintext, ENT_COMPAT, 'UTF-8'); -else - print $plaintext; +print html_entity_decode($converter->get_text(), ENT_COMPAT, 'UTF-8'); ?> diff --git a/bin/modcss.php b/bin/modcss.php index e482389..e97b8ec 100644 --- a/bin/modcss.php +++ b/bin/modcss.php @@ -19,10 +19,8 @@ */ -$INSTALL_PATH = realpath("./../") . "/"; -ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$INSTALL_PATH.'program'.PATH_SEPARATOR.ini_get('include_path')); - -require 'include/main.inc'; +define('INSTALL_PATH', realpath('./../') . '/'); +require INSTALL_PATH.'program/include/iniset.php'; $source = ""; if ($url = preg_replace('/[^a-z0-9.-_\?\$&=%]/i', '', $_GET['u'])) diff --git a/bin/msgexport.sh b/bin/msgexport.sh new file mode 100755 index 0000000..890d48a --- /dev/null +++ b/bin/msgexport.sh @@ -0,0 +1,147 @@ +#!/usr/bin/php -qC +', $pos, $max)); +} + + +// get arguments +$args = get_opt(array('h' => 'host', 'u' => 'user', 'p' => 'pass', 'm' => 'mbox', 'f' => 'file')) + array('host' => 'localhost', 'mbox' => 'INBOX'); + +if ($_SERVER['argv'][1] == 'help') +{ + print_usage(); + exit; +} +else if (!$args['host']) +{ + vputs("Missing required parameters.\n"); + print_usage(); + exit; +} + +// prompt for username if not set +if (empty($args['user'])) +{ + vputs("IMAP user: "); + $args['user'] = trim(fgets(STDIN)); +} + +// prompt for password +vputs("Password: "); +$args['pass'] = trim(fgets(STDIN)); + + +// parse $host URL +$a_host = parse_url($args['host']); +if ($a_host['host']) +{ + $host = $a_host['host']; + $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE; + $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143); +} +else +{ + $host = $args['host']; + $imap_port = 143; +} + +// instantiate IMAP class +$IMAP = new rcube_imap(null); + +// try to connect to IMAP server +if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) +{ + vputs("IMAP login successful.\n"); + + $IMAP->set_mailbox($args['mbox']); + + vputs("Getting message list of {$args['mbox']}..."); + vputs($IMAP->messagecount()." messages\n"); + + if ($args['file']) + { + if (!($out = fopen($args['file'], 'w'))) + { + vputs("Cannot write to output file\n"); + exit; + } + } + else + $out = STDOUT; + + for ($count = $IMAP->messagecount(), $i=1; $i <= $count; $i++) + { + $headers = $IMAP->get_headers($i, null, false); + $from = current($IMAP->decode_address_list($headers->from, 1, false)); + + fwrite($out, sprintf("From %s %s UID %d\n", $from['mailto'], $headers->date, $headers->uid)); + fwrite($out, iil_C_FetchPartHeader($IMAP->conn, $IMAP->mailbox, $i, null)); + fwrite($out, iil_C_HandlePartBody($IMAP->conn, $IMAP->mailbox, $i, null, 1)); + fwrite($out, "\n\n\n"); + + progress_update($i, $count); + } + vputs("\ncomplete.\n"); +} +else +{ + vputs("IMAP login failed.\n"); +} + +?> \ No newline at end of file diff --git a/bin/msgimport b/bin/msgimport deleted file mode 100755 index 0ed268f..0000000 --- a/bin/msgimport +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/php -qC - 'host', 'u' => 'user', 'p' => 'pass', 'f' => 'file')) + array('host' => 'localhost'); - -if ($_SERVER['argv'][1] == 'help') -{ - print_usage(); - exit; -} -else if (!($args['host'] && $args['file'])) -{ - print "Missing required parameters.\n"; - print_usage(); - exit; -} -else if (!is_file($args['file'])) -{ - print "Cannot read message file\n"; - exit; -} - -// prompt for username if not set -if (empty($args['user'])) -{ - //fwrite(STDOUT, "Please enter your name\n"); - echo "IMAP user: "; - $args['user'] = trim(fgets(STDIN)); -} - -// prompt for password -echo "Password: "; -$args['pass'] = trim(fgets(STDIN)); - -// clear password input -echo chr(8)."\rPassword: ".str_repeat("*", strlen($args['pass']))."\n"; - -// parse $host URL -$a_host = parse_url($args['host']); -if ($a_host['host']) -{ - $host = $a_host['host']; - $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE; - $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143); -} -else -{ - $host = $args['host']; - $imap_port = 143; -} - -// instantiate IMAP class -$IMAP = new rcube_imap(null); - -// try to connect to IMAP server -if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) -{ - print "IMAP login successful.\n"; - print "Uploading message...\n"; - - // upload message from file - if ($IMAP->save_message('INBOX', file_get_contents($args['file']))) - print "Message successfully added to INBOX.\n"; - else - print "Adding message failed!\n"; -} -else -{ - print "IMAP login failed.\n"; -} - -?> \ No newline at end of file diff --git a/bin/msgimport.sh b/bin/msgimport.sh new file mode 100755 index 0000000..98a0389 --- /dev/null +++ b/bin/msgimport.sh @@ -0,0 +1,120 @@ +#!/usr/bin/php -qC + 'host', 'u' => 'user', 'p' => 'pass', 'f' => 'file')) + array('host' => 'localhost'); + +if ($_SERVER['argv'][1] == 'help') +{ + print_usage(); + exit; +} +else if (!($args['host'] && $args['file'])) +{ + print "Missing required parameters.\n"; + print_usage(); + exit; +} +else if (!is_file($args['file'])) +{ + print "Cannot read message file\n"; + exit; +} + +// prompt for username if not set +if (empty($args['user'])) +{ + //fwrite(STDOUT, "Please enter your name\n"); + echo "IMAP user: "; + $args['user'] = trim(fgets(STDIN)); +} + +// prompt for password +echo "Password: "; +$args['pass'] = trim(fgets(STDIN)); + +// clear password input +echo chr(8)."\rPassword: ".str_repeat("*", strlen($args['pass']))."\n"; + +// parse $host URL +$a_host = parse_url($args['host']); +if ($a_host['host']) +{ + $host = $a_host['host']; + $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE; + $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143); +} +else +{ + $host = $args['host']; + $imap_port = 143; +} + +// instantiate IMAP class +$IMAP = new rcube_imap(null); + +// try to connect to IMAP server +if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) +{ + print "IMAP login successful.\n"; + print "Uploading message...\n"; + + // upload message from file + if ($IMAP->save_message('INBOX', file_get_contents($args['file']))) + print "Message successfully added to INBOX.\n"; + else + print "Adding message failed!\n"; +} +else +{ + print "IMAP login failed.\n"; +} + +?> \ No newline at end of file diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 962fb4e..67d82c8 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -40,6 +40,10 @@ $rcmail_config['default_host'] = ''; // TCP port used for IMAP connections $rcmail_config['default_port'] = 143; +// IMAP auth type. Can be "auth" (CRAM-MD5), "plain" (PLAIN) or "check" to auto detect. +// Optional, defaults to "check" +$rcmail_config['imap_auth_type'] = null; + // Automatically add this domain to user names for login // Only for IMAP servers that require full e-mail addresses for login // Specify an array with 'host' => 'domain' values to support multiple hosts @@ -118,7 +122,7 @@ $rcmail_config['double_auth'] = false; $rcmail_config['des_key'] = 'rcmail-!24ByteDESkey*Str'; // the default locale setting -$rcmail_config['locale_string'] = 'en'; +$rcmail_config['language'] = 'en'; // use this format for short date display $rcmail_config['date_short'] = 'D H:i'; @@ -130,7 +134,7 @@ $rcmail_config['date_long'] = 'd.m.Y H:i'; $rcmail_config['date_today'] = 'H:i'; // add this user-agent to message headers when sending -$rcmail_config['useragent'] = 'RoundCube Webmail/0.1'; +$rcmail_config['useragent'] = 'RoundCube Webmail/0.2a'; // use this name to compose page titles $rcmail_config['product_name'] = 'RoundCube Webmail'; @@ -213,9 +217,29 @@ $rcmail_config['mail_header_delimiter'] = NULL; // session domain: .example.org $rcmail_config['session_domain'] = ''; -// in order to enable public ldap search, create a config array -// like the Verisign example below. if you would like to test, -// simply uncomment the Verisign example. +// This indicates which type of address book to use. Possible choises: +// 'sql' (default) and 'ldap'. +// If set to 'ldap' then it will look at using the first writable LDAP +// address book as the primary address book and it will not display the +// SQL address book in the 'Address Book' view. +$rcmail_config['address_book_type'] = 'sql'; + +// In order to enable public ldap search, configure an array like the Verisign +// example further below. if you would like to test, simply uncomment the example. +// +// If you are going to use LDAP for individual address books, you will need to +// set 'user_specific' to true and use the variables to generate the appropriate DNs to access it. +// +// The recommended directory structure for LDAP is to store all the address book entries +// under the users main entry, e.g.: +// +// o=root +// ou=people +// uid=user@domain +// mail=contact@contactdomain +// +// So the base_dn would be uid=%fu,ou=people,o=root +// The bind_dn would be the same as based_dn or some super user login. /** * example config for Verisign directory * @@ -223,34 +247,57 @@ $rcmail_config['session_domain'] = ''; * 'name' => 'Verisign.com', * 'hosts' => array('directory.verisign.com'), * 'port' => 389, + * 'use_tls' => false, + * 'user_specific' => false, // If true the base_dn, bind_dn and bind_pass default to the user's IMAP login. + * // %fu - The full username provided, assumes the username is an email + * // address, uses the username_domain value if not an email address. + * // %u - The username prior to the '@'. + * // %d - The domain name after the '@'. * 'base_dn' => '', * 'bind_dn' => '', * 'bind_pass' => '', + * 'writable' => false, // Indicates if we can write to the LDAP directory or not. + * // If writable is true then these fields need to be populated: + * // LDAP_Object_Classes, required_fields, LDAP_rdn + * 'LDAP_Object_Classes' => array("top", "inetOrgPerson"), // To create a new contact these are the object classes to specify (or any other classes you wish to use). + * 'required_fields' => array("cn", "sn", "mail"), // The required fields needed to build a new contact as required by the object classes (can include additional fields not required by the object classes). + * 'LDAP_rdn' => 'mail', // The RDN field that is used for new entries, this field needs to be one of the search_fields, the base of base_dn is appended to the RDN to insert into the LDAP directory. * 'ldap_version' => 3, // using LDAPv3 * 'search_fields' => array('mail', 'cn'), // fields to search in * 'name_field' => 'cn', // this field represents the contact's name * 'email_field' => 'mail', // this field represents the contact's e-mail * 'surname_field' => 'sn', // this field represents the contact's last name * 'firstname_field' => 'gn', // this field represents the contact's first name + * 'sort' => 'cn', // The field to sort the listing by. * 'scope' => 'sub', // search mode: sub|base|list * 'filter' => '', // used for basic listing (if not empty) and will be &'d with search queries. example: status=act + * 'global_search' => true, // perform a global search for address auto-completion on compose * 'fuzzy_search' => true); // server allows wildcard search */ // don't allow these settings to be overriden by the user $rcmail_config['dont_override'] = array(); -// list of configuration option names that need to be available in Javascript. -$rcmail_config['javascript_config'] = array('read_when_deleted', 'flag_for_deletion'); - // try to load host-specific configuration +// see http://trac.roundcube.net/wiki/Howto_Config for more details $rcmail_config['include_host_config'] = false; +// don't let users set pagesize to more than this value if set +$rcmail_config['max_pagesize'] = 200; + +// mime magic database +$rcmail_config['mime_magic'] = '/usr/share/misc/magic'; + +// default sort col +$rcmail_config['message_sort_col'] = 'date'; + +// default sort order +$rcmail_config['message_sort_order'] = 'DESC'; + // THIS OPTION WILL ALLOW THE INSTALLER TO RUN AND CAN EXPOSE SENSITIVE CONFIG DATA. // ONLY ENABLE IT IF YOU'RE REALLY SURE WHAT YOU'RE DOING! $rcmail_config['enable_installer'] = false; - /***** these settings can be overwritten by user's preferences *****/ // show up to X items in list view @@ -271,23 +318,32 @@ $rcmail_config['htmleditor'] = FALSE; // show pretty dates as standard $rcmail_config['prettydate'] = TRUE; -// default sort col -$rcmail_config['message_sort_col'] = 'date'; - -// default sort order -$rcmail_config['message_sort_order'] = 'DESC'; - // save compose message every 300 seconds (5min) $rcmail_config['draft_autosave'] = 300; // default setting if preview pane is enabled $rcmail_config['preview_pane'] = FALSE; -// don't let users set pagesize to more than this value if set -$rcmail_config['max_pagesize'] = 200; +// Clear Trash on logout +$rcmail_config['logout_purge'] = FALSE; -// mime magic database -$rcmail_config['mime_magic'] = '/usr/share/misc/magic'; +// Compact INBOX on logout +$rcmail_config['logout_expunge'] = FALSE; + +/** + * 'Delete always' + * This setting reflects if mail should be always marked as deleted, + * even if moving to "Trash" fails. This is necessary in some setups + * because a) people may not have a Trash folder or b) they are over + * quota (and Trash is included in the quota). + * + * This is a failover setting for iil_C_Move when a message is moved + * to the Trash, and not the same as "delete_right_away". + */ +$rcmail_config['delete_always'] = false; + +// Log successful logins +$rcmail_config['log_logins'] = false; // end of config file ?> diff --git a/index.php b/index.php index 02a6201..f40f701 100644 --- a/index.php +++ b/index.php @@ -1,142 +1,61 @@ | - +-----------------------------------------------------------------------+ - - $Id: index.php 1255 2008-04-05 12:49:21Z thomasb $ + +-------------------------------------------------------------------------+ + | RoundCube Webmail IMAP Client | + | Version 0.2-alpha | + | | + | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland | + | | + | This program is free software; you can redistribute it and/or modify | + | it under the terms of the GNU General Public License version 2 | + | as published by the Free Software Foundation. | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of the GNU General Public License along | + | with this program; if not, write to the Free Software Foundation, Inc., | + | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | + | | + +-------------------------------------------------------------------------+ + | Author: Thomas Bruederli | + +-------------------------------------------------------------------------+ + + $Id: index.php 1499 2008-06-09 20:57:53Z thomasb $ */ -// application constants -define('RCMAIL_VERSION', '0.1.1'); -define('RCMAIL_CHARSET', 'UTF-8'); -define('JS_OBJECT_NAME', 'rcmail'); +// include environment +require_once 'program/include/iniset.php'; // define global vars $OUTPUT_TYPE = 'html'; -$INSTALL_PATH = dirname(__FILE__); -$MAIN_TASKS = array('mail','settings','addressbook','logout'); - -if (empty($INSTALL_PATH)) - $INSTALL_PATH = './'; -else - $INSTALL_PATH .= '/'; - - -// make sure path_separator is defined -if (!defined('PATH_SEPARATOR')) - define('PATH_SEPARATOR', (eregi('win', PHP_OS) ? ';' : ':')); - - -// RC include folders MUST be included FIRST to avoid other -// possible not compatible libraries (i.e PEAR) to be included -// instead the ones provided by RC -ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$INSTALL_PATH.'program'.PATH_SEPARATOR.$INSTALL_PATH.'program/lib'.PATH_SEPARATOR.ini_get('include_path')); - -ini_set('session.name', 'roundcube_sessid'); -ini_set('session.use_cookies', 1); -ini_set('session.gc_maxlifetime', 21600); -ini_set('session.gc_divisor', 500); -ini_set('error_reporting', E_ALL&~E_NOTICE); -set_magic_quotes_runtime(0); - -// increase maximum execution time for php scripts -// (does not work in safe mode) -if (!ini_get('safe_mode')) @set_time_limit(120); - -// include base files -require_once('include/rcube_shared.inc'); -require_once('include/rcube_imap.inc'); -require_once('include/bugs.inc'); -require_once('include/main.inc'); -require_once('PEAR.php'); - - -// set PEAR error handling -// PEAR::setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_NOTICE); - - -// catch some url/post parameters -$_task = strip_quotes(get_input_value('_task', RCUBE_INPUT_GPC)); -$_action = strip_quotes(get_input_value('_action', RCUBE_INPUT_GPC)); -$_framed = (!empty($_GET['_framed']) || !empty($_POST['_framed'])); - -// use main task if empty or invalid value -if (empty($_task) || !in_array($_task, $MAIN_TASKS)) - $_task = 'mail'; - // set output buffering -if ($_action != 'get' && $_action != 'viewsource') -{ +if ($RCMAIL->action != 'get' && $RCMAIL->action != 'viewsource') { // use gzip compression if supported if (function_exists('ob_gzhandler') - && !ini_get('zlib.output_compression') - && ini_get('output_handler') != 'ob_gzhandler') - { + && !ini_get('zlib.output_compression') + && ini_get('output_handler') != 'ob_gzhandler') { ob_start('ob_gzhandler'); } - else + else { ob_start(); + } } -// start session with requested task -rcmail_startup($_task); +// init application and start session with requested task +$RCMAIL = rcmail::get_instance(); -// set session related variables -$COMM_PATH = sprintf('./?_task=%s', $_task); -$SESS_HIDDEN_FIELD = ''; - - -// add framed parameter -if ($_framed) -{ - $COMM_PATH .= '&_framed=1'; - $SESS_HIDDEN_FIELD .= "\n".''; -} - - -// init necessary objects for GUI -rcmail_load_gui(); +// init output class +$OUTPUT = (!empty($_GET['_remote']) || !empty($_POST['_remote'])) ? $RCMAIL->init_json() : $RCMAIL->load_gui((!empty($_GET['_framed']) || !empty($_POST['_framed']))); // check DB connections and exit on failure -if ($err_str = $DB->is_error()) -{ +if ($err_str = $DB->is_error()) { raise_error(array( 'code' => 603, 'type' => 'db', @@ -145,116 +64,102 @@ if ($err_str = $DB->is_error()) // error steps -if ($_action=='error' && !empty($_GET['_code'])) +if ($RCMAIL->action=='error' && !empty($_GET['_code'])) { raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE); - +} // try to log in -if ($_action=='login' && $_task=='mail') -{ - $host = rcmail_autoselect_host(); +if ($RCMAIL->action=='login' && $RCMAIL->task=='mail') { + $host = $RCMAIL->autoselect_host(); // check if client supports cookies - if (empty($_COOKIE)) - { + if (empty($_COOKIE)) { $OUTPUT->show_message("cookiesdisabled", 'warning'); } else if ($_SESSION['temp'] && !empty($_POST['_user']) && isset($_POST['_pass']) && - rcmail_login(trim(get_input_value('_user', RCUBE_INPUT_POST), ' '), - get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host)) - { + $RCMAIL->login(trim(get_input_value('_user', RCUBE_INPUT_POST), ' '), + get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host)) { // create new session ID unset($_SESSION['temp']); sess_regenerate_id(); // send auth cookie if necessary - rcmail_authenticate_session(); + $RCMAIL->authenticate_session(); + + // log successful login + if ($RCMAIL->config->get('log_logins') && $RCMAIL->config->get('debug_level') & 1) + console(sprintf('Successful login for %s (id %d) from %s', + trim(get_input_value('_user', RCUBE_INPUT_POST), ' '), + $_SESSION['user_id'], + $_SERVER['REMOTE_ADDR'])); // send redirect - header("Location: $COMM_PATH"); + header("Location: {$RCMAIL->comm_path}"); exit; } - else - { + else { $OUTPUT->show_message($IMAP->error_code == -1 ? 'imaperror' : 'loginfailed', 'warning'); - rcmail_kill_session(); + $RCMAIL->kill_session(); } } // end session -else if (($_task=='logout' || $_action=='logout') && isset($_SESSION['user_id'])) -{ +else if (($RCMAIL->task=='logout' || $RCMAIL->action=='logout') && isset($_SESSION['user_id'])) { $OUTPUT->show_message('loggedout'); - rcmail_kill_session(); + $RCMAIL->logout_actions(); + $RCMAIL->kill_session(); } // check session and auth cookie -else if ($_action != 'login' && $_SESSION['user_id'] && $_action != 'send') -{ - if (!rcmail_authenticate_session()) - { +else if ($RCMAIL->action != 'login' && $_SESSION['user_id'] && $RCMAIL->action != 'send') { + if (!$RCMAIL->authenticate_session()) { $OUTPUT->show_message('sessionerror', 'error'); - rcmail_kill_session(); + $RCMAIL->kill_session(); } } // log in to imap server -if (!empty($USER->ID) && $_task=='mail') -{ - $conn = $IMAP->connect($_SESSION['imap_host'], $_SESSION['username'], decrypt_passwd($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl']); - if (!$conn) - { - $OUTPUT->show_message($IMAP->error_code == -1 ? 'imaperror' : 'sessionerror', 'error'); - rcmail_kill_session(); +if (!empty($RCMAIL->user->ID) && $RCMAIL->task == 'mail') { + if (!$RCMAIL->imap_connect()) { + $RCMAIL->kill_session(); } - else - rcmail_set_imap_prop(); } // not logged in -> set task to 'login -if (empty($USER->ID)) -{ +if (empty($RCMAIL->user->ID)) { if ($OUTPUT->ajax_call) $OUTPUT->remote_response("setTimeout(\"location.href='\"+this.env.comm_path+\"'\", 2000);"); - $_task = 'login'; + $RCMAIL->set_task('login'); } // check client X-header to verify request origin -if ($OUTPUT->ajax_call) -{ - if (empty($CONFIG['devel_mode']) && !rc_request_header('X-RoundCube-Referer')) - { +if ($OUTPUT->ajax_call) { + if (empty($CONFIG['devel_mode']) && !rc_request_header('X-RoundCube-Referer')) { header('HTTP/1.1 404 Not Found'); die("Invalid Request"); } } -// set task and action to client -$OUTPUT->set_env('task', $_task); -if (!empty($_action)) - $OUTPUT->set_env('action', $_action); - - - // not logged in -> show login page -if (empty($USER->ID)) -{ +if (empty($RCMAIL->user->ID)) { // check if installer is still active - if ($CONFIG['enable_installer'] && is_readable('./installer/index.php')) - $OUTPUT->add_footer(' -
-

Installer script is still accessible

-

The install script of your RoundCube installation is still stored in its default location!

-

Please remove the whole installer folder from the RoundCube directory because - these files may expose sensitive configuration data like server passwords and encryption keys - to the public. Make sure you cannot access the installer script from your browser.

-
'); + if ($CONFIG['enable_installer'] && is_readable('./installer/index.php')) { + $OUTPUT->add_footer(html::div(array('style' => "background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em"), + html::tag('h2', array('style' => "margin-top:0.2em"), "Installer script is still accessible") . + html::p(null, "The install script of your RoundCube installation is still stored in its default location!") . + html::p(null, "Please remove the whole installer folder from the RoundCube directory because . + these files may expose sensitive configuration data like server passwords and encryption keys + to the public. Make sure you cannot access the installer script from your browser.") + ) + ); + } + $OUTPUT->set_env('task', 'login'); $OUTPUT->task = 'login'; $OUTPUT->send('login'); exit; @@ -262,138 +167,129 @@ if (empty($USER->ID)) // handle keep-alive signal -if ($_action=='keep-alive') -{ +if ($RCMAIL->action=='keep-alive') { $OUTPUT->reset(); $OUTPUT->send(''); exit; } // include task specific files -if ($_task=='mail') -{ +if ($RCMAIL->task=='mail') { include_once('program/steps/mail/func.inc'); - if ($_action=='show' || $_action=='preview' || $_action=='print') + if ($RCMAIL->action=='show' || $RCMAIL->action=='preview' || $RCMAIL->action=='print') include('program/steps/mail/show.inc'); - if ($_action=='get') + if ($RCMAIL->action=='get') include('program/steps/mail/get.inc'); - if ($_action=='moveto' || $_action=='delete') + if ($RCMAIL->action=='moveto' || $RCMAIL->action=='delete') include('program/steps/mail/move_del.inc'); - if ($_action=='mark') + if ($RCMAIL->action=='mark') include('program/steps/mail/mark.inc'); - if ($_action=='viewsource') + if ($RCMAIL->action=='viewsource') include('program/steps/mail/viewsource.inc'); - if ($_action=='sendmdn') + if ($RCMAIL->action=='sendmdn') include('program/steps/mail/sendmdn.inc'); - if ($_action=='send') + if ($RCMAIL->action=='send') include('program/steps/mail/sendmail.inc'); - if ($_action=='upload') + if ($RCMAIL->action=='upload') include('program/steps/mail/upload.inc'); - if ($_action=='compose' || $_action=='remove-attachment' || $_action=='display-attachment') + if ($RCMAIL->action=='compose' || $RCMAIL->action=='remove-attachment' || $RCMAIL->action=='display-attachment') include('program/steps/mail/compose.inc'); - if ($_action=='addcontact') + if ($RCMAIL->action=='addcontact') include('program/steps/mail/addcontact.inc'); - if ($_action=='expunge' || $_action=='purge') + if ($RCMAIL->action=='expunge' || $RCMAIL->action=='purge') include('program/steps/mail/folders.inc'); - if ($_action=='check-recent') + if ($RCMAIL->action=='check-recent') include('program/steps/mail/check_recent.inc'); - if ($_action=='getunread') + if ($RCMAIL->action=='getunread') include('program/steps/mail/getunread.inc'); - if ($_action=='list' && isset($_REQUEST['_remote'])) + if ($RCMAIL->action=='list' && isset($_REQUEST['_remote'])) include('program/steps/mail/list.inc'); - if ($_action=='search') + if ($RCMAIL->action=='search') include('program/steps/mail/search.inc'); - if ($_action=='spell') + if ($RCMAIL->action=='spell') include('program/steps/mail/spell.inc'); - if ($_action=='rss') + if ($RCMAIL->action=='rss') include('program/steps/mail/rss.inc'); - if ($_action=='quotadisplay') - include('program/steps/mail/quotadisplay.inc'); - - // make sure the message count is refreshed - $IMAP->messagecount($_SESSION['mbox'], 'ALL', TRUE); + $IMAP->messagecount($_SESSION['mbox'], 'ALL', true); } // include task specific files -if ($_task=='addressbook') -{ +if ($RCMAIL->task=='addressbook') { include_once('program/steps/addressbook/func.inc'); - if ($_action=='save') + if ($RCMAIL->action=='save') include('program/steps/addressbook/save.inc'); - if ($_action=='edit' || $_action=='add') + if ($RCMAIL->action=='edit' || $RCMAIL->action=='add') include('program/steps/addressbook/edit.inc'); - if ($_action=='delete') + if ($RCMAIL->action=='delete') include('program/steps/addressbook/delete.inc'); - if ($_action=='show') + if ($RCMAIL->action=='show') include('program/steps/addressbook/show.inc'); - if ($_action=='list' && $_REQUEST['_remote']) + if ($RCMAIL->action=='list' && $_REQUEST['_remote']) include('program/steps/addressbook/list.inc'); - if ($_action=='search') + if ($RCMAIL->action=='search') include('program/steps/addressbook/search.inc'); - if ($_action=='copy') + if ($RCMAIL->action=='copy') include('program/steps/addressbook/copy.inc'); - if ($_action=='mailto') + if ($RCMAIL->action=='mailto') include('program/steps/addressbook/mailto.inc'); } // include task specific files -if ($_task=='settings') -{ +if ($RCMAIL->task=='settings') { include_once('program/steps/settings/func.inc'); - if ($_action=='save-identity') + if ($RCMAIL->action=='save-identity') include('program/steps/settings/save_identity.inc'); - if ($_action=='add-identity' || $_action=='edit-identity') + if ($RCMAIL->action=='add-identity' || $RCMAIL->action=='edit-identity') include('program/steps/settings/edit_identity.inc'); - if ($_action=='delete-identity') + if ($RCMAIL->action=='delete-identity') include('program/steps/settings/delete_identity.inc'); - if ($_action=='identities') + if ($RCMAIL->action=='identities') include('program/steps/settings/identities.inc'); - if ($_action=='save-prefs') + if ($RCMAIL->action=='save-prefs') include('program/steps/settings/save_prefs.inc'); - if ($_action=='folders' || $_action=='subscribe' || $_action=='unsubscribe' || - $_action=='create-folder' || $_action=='rename-folder' || $_action=='delete-folder') + if ($RCMAIL->action=='folders' || $RCMAIL->action=='subscribe' || $RCMAIL->action=='unsubscribe' || + $RCMAIL->action=='create-folder' || $RCMAIL->action=='rename-folder' || $RCMAIL->action=='delete-folder') include('program/steps/settings/manage_folders.inc'); - } // parse main template -$OUTPUT->send($_task); +$OUTPUT->send($RCMAIL->task); // if we arrive here, something went wrong @@ -402,6 +298,6 @@ raise_error(array( 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__, - 'message' => "Invalid request"), TRUE, TRUE); + 'message' => "Invalid request"), true, true); ?> diff --git a/installer/._config.php b/installer/._config.php new file mode 100644 index 0000000..4ee59dc Binary files /dev/null and b/installer/._config.php differ diff --git a/installer/check.php b/installer/check.php index e671c06..3b64af3 100644 --- a/installer/check.php +++ b/installer/check.php @@ -1,13 +1,16 @@
'pcre', 'Session' => 'session'); +$required_php_exts = array('PCRE' => 'pcre', 'Session' => 'session', + 'DOM XML' => 'dom'); $optional_php_exts = array('FileInfo' => 'fileinfo', 'Libiconv' => 'iconv', - 'Multibyte' => 'mbstring', 'OpenSSL' => 'openssl', 'Mcrypt' => 'mcrypt', 'GD' => 'gd'); + 'Multibyte' => 'mbstring', 'OpenSSL' => 'openssl', 'Mcrypt' => 'mcrypt', + 'GD' => 'gd'); $required_libs = array('PEAR' => 'PEAR.php', 'DB' => 'DB.php', 'MDB2' => 'MDB2.php', - 'Net_SMTP' => 'Net/SMTP.php', 'Mail_mime' => 'Mail/mime.php', 'iilConnection' => 'lib/imap.inc'); + 'Net_SMTP' => 'Net/SMTP.php', 'Mail_mime' => 'Mail/mime.php', + 'iilConnection' => 'lib/imap.inc'); $supported_dbs = array('MySQL' => 'mysql', 'MySQLi' => 'mysqli', 'PostgreSQL' => 'pgsql', 'SQLite (v2)' => 'sqlite'); @@ -37,11 +40,10 @@ echo ' load_defaults(); @@ -25,16 +22,16 @@ $_SESSION['allowinstaller'] = true; if (!empty($_POST['submit'])) { - echo '

Copy the following configurations and save them in two files (names above the text box)'; - echo ' within the config/ directory of your RoundCube installation.
'; + echo '

Copy or download the following configurations and save them in two files'; + echo ' (names above the text box) within the config/ directory of your RoundCube installation.
'; echo ' Make sure that there are no characters outside the <?php ?> brackets when saving the files.

'; - $textbox = new textarea(array('rows' => 16, 'cols' => 60, 'class' => "configfile")); + $textbox = new html_textarea(array('rows' => 16, 'cols' => 60, 'class' => "configfile")); - echo '
main.inc.php
'; + echo '
main.inc.php (download)
'; echo $textbox->show($RCI->create_config('main')); - echo '
db.inc.php
'; + echo '
db.inc.php (download)
'; echo $textbox->show($RCI->create_config('db')); echo '

Of course there are more options to configure. @@ -56,7 +53,7 @@ if (!empty($_POST['submit'])) { getprop('debug_level'); -$check_debug = new checkbox(array('name' => '_debug_level[]')); +$check_debug = new html_checkbox(array('name' => '_debug_level[]')); echo $check_debug->show(($value & 1) ? 1 : 0 , array('value' => 1, 'id' => 'cfgdebug1')); echo '
'; @@ -74,7 +71,7 @@ echo '
';

'_product_name', 'size' => 30, 'id' => "cfgprodname")); +$input_prodname = new html_inputfield(array('name' => '_product_name', 'size' => 30, 'id' => "cfgprodname")); echo $input_prodname->show($RCI->getprop('product_name')); ?> @@ -85,7 +82,7 @@ echo $input_prodname->show($RCI->getprop('product_name'));
'_skin_path', 'size' => 30, 'id' => "cfgskinpath")); +$input_skinpath = new html_inputfield(array('name' => '_skin_path', 'size' => 30, 'id' => "cfgskinpath")); echo $input_skinpath->show($RCI->getprop('skin_path')); ?> @@ -96,7 +93,7 @@ echo $input_skinpath->show($RCI->getprop('skin_path'));
'_temp_dir', 'size' => 30, 'id' => "cfgtempdir")); +$input_tempdir = new html_inputfield(array('name' => '_temp_dir', 'size' => 30, 'id' => "cfgtempdir")); echo $input_tempdir->show($RCI->getprop('temp_dir')); ?> @@ -107,7 +104,7 @@ echo $input_tempdir->show($RCI->getprop('temp_dir'));
'_log_dir', 'size' => 30, 'id' => "cfglogdir")); +$input_logdir = new html_inputfield(array('name' => '_log_dir', 'size' => 30, 'id' => "cfglogdir")); echo $input_logdir->show($RCI->getprop('log_dir')); ?> @@ -118,7 +115,7 @@ echo $input_logdir->show($RCI->getprop('log_dir'));
'_ip_check', 'id' => "cfgipcheck")); +$check_ipcheck = new html_checkbox(array('name' => '_ip_check', 'id' => "cfgipcheck")); echo $check_ipcheck->show(intval($RCI->getprop('ip_check')), array('value' => 1)); ?> @@ -131,7 +128,7 @@ echo $check_ipcheck->show(intval($RCI->getprop('ip_check')), array('value' => 1)
'_des_key', 'size' => 30, 'id' => "cfgdeskey")); +$input_deskey = new html_inputfield(array('name' => '_des_key', 'size' => 30, 'id' => "cfgdeskey")); echo $input_deskey->show($RCI->getprop('des_key')); ?> @@ -144,7 +141,7 @@ If you enter it manually please provide a string of exactly 24 chars.

'_enable_caching', 'id' => "cfgcache")); +$check_caching = new html_checkbox(array('name' => '_enable_caching', 'id' => "cfgcache")); echo $check_caching->show(intval($RCI->getprop('enable_caching')), array('value' => 1)); ?> @@ -155,7 +152,7 @@ echo $check_caching->show(intval($RCI->getprop('enable_caching')), array('value'
'_enable_spellcheck', 'id' => "cfgspellcheck")); +$check_caching = new html_checkbox(array('name' => '_enable_spellcheck', 'id' => "cfgspellcheck")); echo $check_caching->show(intval($RCI->getprop('enable_spellcheck')), array('value' => 1)); ?> @@ -168,7 +165,7 @@ echo $check_caching->show(intval($RCI->getprop('enable_spellcheck')), array('val
'_mdn_requests', 'id' => "cfgmdnreq")); +$select_mdnreq = new html_select(array('name' => '_mdn_requests', 'id' => "cfgmdnreq")); $select_mdnreq->add(array('ask the user', 'send automatically', 'ignore'), array(0, 1, 2)); echo $select_mdnreq->show(intval($RCI->getprop('mdn_requests'))); @@ -187,24 +184,24 @@ echo $select_mdnreq->show(intval($RCI->getprop('mdn_requests')));

Database settings for read/write operations:

'mysql', 'MySQLi' => 'mysqli', 'PgSQL' => 'pgsql', 'SQLite' => 'sqlite'); -$select_dbtype = new select(array('name' => '_dbtype', 'id' => "cfgdbtype")); +$select_dbtype = new html_select(array('name' => '_dbtype', 'id' => "cfgdbtype")); foreach ($supported_dbs AS $database => $ext) { if (extension_loaded($ext)) { $select_dbtype->add($database, $ext); } } -$input_dbhost = new textfield(array('name' => '_dbhost', 'size' => 20, 'id' => "cfgdbhost")); -$input_dbname = new textfield(array('name' => '_dbname', 'size' => 20, 'id' => "cfgdbname")); -$input_dbuser = new textfield(array('name' => '_dbuser', 'size' => 20, 'id' => "cfgdbuser")); -$input_dbpass = new textfield(array('name' => '_dbpass', 'size' => 20, 'id' => "cfgdbpass")); +$input_dbhost = new html_inputfield(array('name' => '_dbhost', 'size' => 20, 'id' => "cfgdbhost")); +$input_dbname = new html_inputfield(array('name' => '_dbname', 'size' => 20, 'id' => "cfgdbname")); +$input_dbuser = new html_inputfield(array('name' => '_dbuser', 'size' => 20, 'id' => "cfgdbuser")); +$input_dbpass = new html_passwordfield(array('name' => '_dbpass', 'size' => 20, 'id' => "cfgdbpass")); -$dsnw = DB::parseDSN($RCI->getprop('db_dsnw')); +$dsnw = MDB2::parseDSN($RCI->getprop('db_dsnw')); echo $select_dbtype->show($RCI->is_post ? $_POST['_dbtype'] : $dsnw['phptype']); echo '
'; @@ -228,7 +225,7 @@ echo '
'; @include_once 'DB.php'; @include_once 'MDB2.php'; -$select_dbba = new select(array('name' => '_db_backend', 'id' => "cfgdbba")); +$select_dbba = new html_select(array('name' => '_db_backend', 'id' => "cfgdbba")); if (class_exists('DB')) $select_dbba->add('DB', 'db'); @@ -254,7 +251,7 @@ echo $select_dbba->show($RCI->getprop('db_backend'));
'_default_host[]', 'size' => 30)); +$text_imaphost = new html_inputfield(array('name' => '_default_host[]', 'size' => 30)); $default_hosts = $RCI->get_hostlist(); if (empty($default_hosts)) @@ -279,7 +276,7 @@ foreach ($default_hosts as $host) {
'_default_port', 'size' => 6, 'id' => "cfgimapport")); +$text_imapport = new html_inputfield(array('name' => '_default_port', 'size' => 6, 'id' => "cfgimapport")); echo $text_imapport->show($RCI->getprop('default_port')); ?> @@ -290,7 +287,7 @@ echo $text_imapport->show($RCI->getprop('default_port'));
'_username_domain', 'size' => 30, 'id' => "cfguserdomain")); +$text_userdomain = new html_inputfield(array('name' => '_username_domain', 'size' => 30, 'id' => "cfguserdomain")); echo $text_userdomain->show($RCI->getprop('username_domain')); ?> @@ -303,7 +300,7 @@ echo $text_userdomain->show($RCI->getprop('username_domain'));
'_auto_create_user', 'id' => "cfgautocreate")); +$check_autocreate = new html_checkbox(array('name' => '_auto_create_user', 'id' => "cfgautocreate")); echo $check_autocreate->show(intval($RCI->getprop('auto_create_user')), array('value' => 1)); ?> @@ -320,7 +317,7 @@ what means that you have to create those records manually or disable this option
'_sent_mbox', 'size' => 20, 'id' => "cfgsentmbox")); +$text_sentmbox = new html_inputfield(array('name' => '_sent_mbox', 'size' => 20, 'id' => "cfgsentmbox")); echo $text_sentmbox->show($RCI->getprop('sent_mbox')); ?> @@ -333,7 +330,7 @@ echo $text_sentmbox->show($RCI->getprop('sent_mbox'));
'_trash_mbox', 'size' => 20, 'id' => "cfgtrashmbox")); +$text_trashmbox = new html_inputfield(array('name' => '_trash_mbox', 'size' => 20, 'id' => "cfgtrashmbox")); echo $text_trashmbox->show($RCI->getprop('trash_mbox')); ?> @@ -346,7 +343,7 @@ echo $text_trashmbox->show($RCI->getprop('trash_mbox'));
'_drafts_mbox', 'size' => 20, 'id' => "cfgdraftsmbox")); +$text_draftsmbox = new html_inputfield(array('name' => '_drafts_mbox', 'size' => 20, 'id' => "cfgdraftsmbox")); echo $text_draftsmbox->show($RCI->getprop('drafts_mbox')); ?> @@ -364,7 +361,7 @@ echo $text_draftsmbox->show($RCI->getprop('drafts_mbox'));
'_smtp_server', 'size' => 30, 'id' => "cfgsmtphost")); +$text_smtphost = new html_inputfield(array('name' => '_smtp_server', 'size' => 30, 'id' => "cfgsmtphost")); echo $text_smtphost->show($RCI->getprop('smtp_server')); ?> @@ -377,7 +374,7 @@ echo $text_smtphost->show($RCI->getprop('smtp_server'));
'_smtp_port', 'size' => 6, 'id' => "cfgsmtpport")); +$text_smtpport = new html_inputfield(array('name' => '_smtp_port', 'size' => 6, 'id' => "cfgsmtpport")); echo $text_smtpport->show($RCI->getprop('smtp_port')); ?> @@ -388,8 +385,8 @@ echo $text_smtpport->show($RCI->getprop('smtp_port'));
'_smtp_user', 'size' => 20, 'id' => "cfgsmtpuser")); -$text_smtppass = new textfield(array('name' => '_smtp_pass', 'size' => 20, 'id' => "cfgsmtppass")); +$text_smtpuser = new html_inputfield(array('name' => '_smtp_user', 'size' => 20, 'id' => "cfgsmtpuser")); +$text_smtppass = new html_passwordfield(array('name' => '_smtp_pass', 'size' => 20, 'id' => "cfgsmtppass")); echo $text_smtpuser->show($RCI->getprop('smtp_user')); echo $text_smtppass->show($RCI->getprop('smtp_pass')); @@ -398,7 +395,7 @@ echo $text_smtppass->show($RCI->getprop('smtp_pass'));

'_smtp_user_u', 'id' => "cfgsmtpuseru")); +$check_smtpuser = new html_checkbox(array('name' => '_smtp_user_u', 'id' => "cfgsmtpuseru")); echo $check_smtpuser->show($RCI->getprop('smtp_user') == '%u' || $_POST['_smtp_user_u'] ? 1 : 0, array('value' => 1)); ?> @@ -410,7 +407,7 @@ echo $check_smtpuser->show($RCI->getprop('smtp_user') == '%u' || $_POST['_smtp_u

'_smtp_auth_type', 'id' => "cfgsmtpauth")); +$select_smtpauth = new html_select(array('name' => '_smtp_auth_type', 'id' => "cfgsmtpauth")); $select_smtpauth->add(array('(auto)', 'PLAIN', 'DIGEST-MD5', 'CRAM-MD5', 'LOGIN'), array('0', 'PLAIN', 'DIGEST-MD5', 'CRAM-MD5', 'LOGIN')); echo $select_smtpauth->show(intval($RCI->getprop('smtp_auth_type'))); */ @@ -422,7 +419,7 @@ echo $select_smtpauth->show(intval($RCI->getprop('smtp_auth_type')));
'_smtp_log', 'id' => "cfgsmtplog")); +$check_smtplog = new html_checkbox(array('name' => '_smtp_log', 'id' => "cfgsmtplog")); echo $check_smtplog->show(intval($RCI->getprop('smtp_log')), array('value' => 1)); ?> @@ -441,7 +438,7 @@ echo $check_smtplog->show(intval($RCI->getprop('smtp_log')), array('value' => 1)
'_locale_string', 'size' => 6, 'id' => "cfglocale")); +$input_locale = new html_inputfield(array('name' => '_locale_string', 'size' => 6, 'id' => "cfglocale")); echo $input_locale->show($RCI->getprop('locale_string')); ?> @@ -453,7 +450,7 @@ echo $input_locale->show($RCI->getprop('locale_string'));
'_pagesize', 'size' => 6, 'id' => "cfgpagesize")); +$input_pagesize = new html_inputfield(array('name' => '_pagesize', 'size' => 6, 'id' => "cfgpagesize")); echo $input_pagesize->show($RCI->getprop('pagesize')); ?> @@ -464,7 +461,7 @@ echo $input_pagesize->show($RCI->getprop('pagesize'));
'_prefer_html', 'id' => "cfghtmlview", 'value' => 1)); +$check_htmlview = new html_checkbox(array('name' => '_prefer_html', 'id' => "cfghtmlview", 'value' => 1)); echo $check_htmlview->show(intval($RCI->getprop('prefer_html'))); ?> @@ -475,7 +472,7 @@ echo $check_htmlview->show(intval($RCI->getprop('prefer_html')));
'_preview_pane', 'id' => "cfgprevpane", 'value' => 1)); +$check_prevpane = new html_checkbox(array('name' => '_preview_pane', 'id' => "cfgprevpane", 'value' => 1)); echo $check_prevpane->show(intval($RCI->getprop('preview_pane'))); ?> @@ -486,7 +483,7 @@ echo $check_prevpane->show(intval($RCI->getprop('preview_pane')));
'_htmleditor', 'id' => "cfghtmlcompose", 'value' => 1)); +$check_htmlcomp = new html_checkbox(array('name' => '_htmleditor', 'id' => "cfghtmlcompose", 'value' => 1)); echo $check_htmlcomp->show(intval($RCI->getprop('htmleditor'))); ?> @@ -498,7 +495,7 @@ echo $check_htmlcomp->show(intval($RCI->getprop('htmleditor'))); '_draft_autosave', 'id' => 'cfgautosave')); +$select_autosave = new html_select(array('name' => '_draft_autosave', 'id' => 'cfgautosave')); $select_autosave->add('never', 0); foreach (array(3, 5, 10) as $i => $min) $select_autosave->add("$min min", $min*60); diff --git a/installer/index.php b/installer/index.php index 69e33f8..4bd37f3 100644 --- a/installer/index.php +++ b/installer/index.php @@ -1,3 +1,31 @@ + @@ -23,22 +51,13 @@
load_config(); // exit if installation is complete if ($RCI->configured && !$RCI->getprop('enable_installer') && !$_SESSION['allowinstaller']) { - header("HTTP/1.0 404 Not Found"); + // header("HTTP/1.0 404 Not Found"); echo '

The installer is disabled!

'; echo '

To enable it again, set $rcmail_config[\'enable_installer\'] = true; in config/main.inc.php

'; echo '
'; diff --git a/installer/rcube_install.php b/installer/rcube_install.php index 12cd5c1..0240467 100644 --- a/installer/rcube_install.php +++ b/installer/rcube_install.php @@ -102,7 +102,7 @@ class rcube_install { $value = $this->is_post && (isset($_POST["_$name"]) || $this->config_props[$name]) ? $_POST["_$name"] : $this->config[$name]; - if ($name == 'des_key' && !isset($_REQUEST["_$name"])) + if ($name == 'des_key' && !$this->configured && !isset($_REQUEST["_$name"])) $value = rcube_install::random_key(24); return $value !== null && $value !== '' ? $value : $default; @@ -137,7 +137,9 @@ class rcube_install if ($_POST['_dbtype'] == 'sqlite') $value = sprintf('%s://%s?mode=0646', $_POST['_dbtype'], $_POST['_dbname']{0} == '/' ? '/' . $_POST['_dbname'] : $_POST['_dbname']); else - $value = sprintf('%s://%s:%s@%s/%s', $_POST['_dbtype'], $_POST['_dbuser'], $_POST['_dbpass'], $_POST['_dbhost'], $_POST['_dbname']); + $value = sprintf('%s://%s:%s@%s/%s', $_POST['_dbtype'], + rawurlencode($_POST['_dbuser']), rawurlencode($_POST['_dbpass']), + $_POST['_dbhost'], $_POST['_dbname']); } else if ($prop == 'smtp_auth_type' && $value == '0') { $value = ''; @@ -147,6 +149,9 @@ class rcube_install if (count($value) <= 1) $value = $value[0]; } + else if ($prop == 'pagesize') { + $value = max(2, intval($value)); + } else if ($prop == 'smtp_user' && !empty($_POST['_smtp_user_u'])) { $value = '%u'; } diff --git a/installer/test.php b/installer/test.php index 5be343a..bdaf3ee 100644 --- a/installer/test.php +++ b/installer/test.php @@ -3,10 +3,8 @@

Check config files

config)) { $RCI->pass('main.inc.php'); @@ -38,7 +36,7 @@ else if (!$read_db) { if ($RCI->configured) { $pass = false; foreach (array($RCI->config['temp_dir'],$RCI->config['log_dir']) as $dir) { - $dirpath = $dir{0} == '/' ? $dir : $docroot . '/' . $dir; + $dirpath = $dir{0} == '/' ? $dir : INSTALL_PATH . $dir; if (is_writable(realpath($dirpath))) { $RCI->pass($dir); $pass = true; @@ -68,10 +66,9 @@ if ($RCI->configured) { echo 'Backend: '; echo 'PEAR::' . strtoupper($RCI->config['db_backend']) . '
'; - $_class = 'rcube_' . strtolower($RCI->config['db_backend']); - require_once 'include/' . $_class . '.inc'; + $dbclass = 'rcube_' . strtolower($RCI->config['db_backend']); - $DB = new $_class($RCI->config['db_dsnw'], '', false); + $DB = new $dbclass($RCI->config['db_dsnw'], '', false); $DB->db_connect('w'); if (!($db_error_msg = $DB->is_error())) { $RCI->pass('DSN (write)'); @@ -164,11 +161,11 @@ if ($RCI->getprop('smtp_server')) { $pass = $RCI->getprop('smtp_pass', '(none)'); if ($user == '%u') { - $user_field = new textfield(array('name' => '_smtp_user')); + $user_field = new html_inputfield(array('name' => '_smtp_user')); $user = $user_field->show($_POST['_smtp_user']); } if ($pass == '%p') { - $pass_field = new passwordfield(array('name' => '_smtp_pass')); + $pass_field = new html_passwordfield(array('name' => '_smtp_pass')); $pass = $pass_field->show(); } @@ -176,8 +173,8 @@ if ($RCI->getprop('smtp_server')) { echo "Password: $pass
"; } -$from_field = new textfield(array('name' => '_from', 'id' => 'sendmailfrom')); -$to_field = new textfield(array('name' => '_to', 'id' => 'sendmailto')); +$from_field = new html_inputfield(array('name' => '_from', 'id' => 'sendmailfrom')); +$to_field = new html_inputfield(array('name' => '_to', 'id' => 'sendmailto')); ?>

@@ -186,8 +183,7 @@ $to_field = new textfield(array('name' => '_to', 'id' => 'sendmailto')); if (isset($_POST['sendmail']) && !empty($_POST['_from']) && !empty($_POST['_to'])) { - require_once 'lib/rc_mail_mime.inc'; - require_once 'include/rcube_smtp.inc'; + require_once 'rcube_smtp.inc'; echo '

Trying to send email...
'; @@ -214,7 +210,7 @@ if (isset($_POST['sendmail']) && !empty($_POST['_from']) && !empty($_POST['_to'] $CONFIG['smtp_pass'] = $_POST['_smtp_pass']; } - $mail_object = new rc_mail_mime(); + $mail_object = new rcube_mail_mime(); $send_headers = $mail_object->headers($headers); $status = smtp_mail($headers['From'], $headers['To'], @@ -271,15 +267,15 @@ echo '

'; $default_hosts = $RCI->get_hostlist(); if (!empty($default_hosts)) { - $host_field = new select(array('name' => '_host', 'id' => 'imaphost')); + $host_field = new html_select(array('name' => '_host', 'id' => 'imaphost')); $host_field->add($default_hosts); } else { - $host_field = new textfield(array('name' => '_host', 'id' => 'imaphost')); + $host_field = new html_inputfield(array('name' => '_host', 'id' => 'imaphost')); } -$user_field = new textfield(array('name' => '_user', 'id' => 'imapuser')); -$pass_field = new passwordfield(array('name' => '_pass', 'id' => 'imappass')); +$user_field = new html_inputfield(array('name' => '_user', 'id' => 'imapuser')); +$pass_field = new html_passwordfield(array('name' => '_pass', 'id' => 'imappass')); ?> @@ -308,8 +304,6 @@ $pass_field = new passwordfield(array('name' => '_pass', 'id' => 'imappass')); if (isset($_POST['imaptest']) && !empty($_POST['_host']) && !empty($_POST['_user'])) { - require_once 'include/rcube_imap.inc'; - echo '

Connecting to ' . Q($_POST['_host']) . '...
'; $a_host = parse_url($_POST['_host']); diff --git a/installer/welcome.html b/installer/welcome.html index 200f680..bfec233 100644 --- a/installer/welcome.html +++ b/installer/welcome.html @@ -6,7 +6,7 @@

The basic requirements are:

    -
  • PHP Version 4.3.1 or greater including +
  • PHP Version 5.2.0 or greater including
    • PCRE (perl compatible regular expression)
    • Session support
    • diff --git a/program/include/._main.inc b/program/include/._main.inc new file mode 100644 index 0000000..f28074c Binary files /dev/null and b/program/include/._main.inc differ diff --git a/program/include/bugs.inc b/program/include/bugs.inc index 4a3cdec..6987a20 100644 --- a/program/include/bugs.inc +++ b/program/include/bugs.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: bugs.inc 666 2007-08-07 21:02:12Z thomasb $ + $Id: bugs.inc 1291 2008-04-12 13:54:45Z thomasb $ */ @@ -66,7 +66,7 @@ function raise_error($arg=array(), $log=false, $terminate=false) */ function log_bug($arg_arr) { - global $CONFIG, $INSTALL_PATH; + global $CONFIG; $program = $arg_arr['type']=='xpath' ? 'XPath' : strtoupper($arg_arr['type']); // write error to local log file @@ -81,7 +81,7 @@ function log_bug($arg_arr) $arg_arr['line']); if (empty($CONFIG['log_dir'])) - $CONFIG['log_dir'] = $INSTALL_PATH.'logs'; + $CONFIG['log_dir'] = INSTALL_PATH.'logs'; // try to open specific log file for writing if ($fp = @fopen($CONFIG['log_dir'].'/errors', 'a')) diff --git a/program/include/html.php b/program/include/html.php new file mode 100644 index 0000000..d0ab976 --- /dev/null +++ b/program/include/html.php @@ -0,0 +1,642 @@ + | + +-----------------------------------------------------------------------+ + + $Id: $ + + */ + + +/** + * Class for HTML code creation + * + * @package HTML + */ +class html +{ + protected $tagname; + protected $attrib = array(); + protected $allowed; + protected $content; + + public static $common_attrib = array('id','class','style','title','align'); + public static $containers = array('div','span','p','h1','h2','h3','form','textarea'); + public static $lc_tags = true; + + /** + * Constructor + * + * @param array Hash array with tag attributes + */ + public function __construct($attrib = array()) + { + if (is_array($attrib)) { + $this->attrib = $attrib; + } + } + + /** + * Return the tag code + * + * @return string The finally composed HTML tag + */ + public function show() + { + return self::tag($this->tagname, $this->attrib, $this->content, $this->allowed); + } + + /****** STATIC METHODS *******/ + + /** + * Generic method to create a HTML tag + * + * @param string Tag name + * @param array Tag attributes as key/value pairs + * @param string Optinal Tag content (creates a container tag) + * @param array List with allowed attributes, omit to allow all + * @return string The XHTML tag + */ + public static function tag($tagname, $attrib = array(), $content = null, $allowed_attrib = null) + { + $inline_tags = array('a','span','img'); + $suffix = $attrib['nl'] || ($content && $attrib['nl'] !== false && !in_array($tagname, $inline_tags)) ? "\n" : ''; + + $tagname = self::$lc_tags ? strtolower($tagname) : $tagname; + if ($content || in_array($tagname, self::$containers)) { + $templ = $attrib['noclose'] ? "<%s%s>%s" : "<%s%s>%s%s"; + unset($attrib['noclose']); + return sprintf($templ, $tagname, self::attrib_string($attrib, $allowed_attrib), $content, $tagname, $suffix); + } + else { + return sprintf("<%s%s />%s", $tagname, self::attrib_string($attrib, $allowed_attrib), $suffix); + } + } + + /** + * Derrived method for
      containers + * + * @param mixed Hash array with tag attributes or string with class name + * @param string Div content + * @return string HTML code + * @see html::tag() + */ + public static function div($attr = null, $cont = null) + { + if (is_string($attr)) { + $attr = array('class' => $attr); + } + return self::tag('div', $attr, $cont, self::$common_attrib); + } + + /** + * Derrived method for

      blocks + * + * @param mixed Hash array with tag attributes or string with class name + * @param string Paragraph content + * @return string HTML code + * @see html::tag() + */ + public static function p($attr = null, $cont = null) + { + if (is_string($attr)) { + $attr = array('class' => $attr); + } + return self::tag('p', $attr, $cont, self::$common_attrib); + } + + /** + * Derrived method to create + * + * @param mixed Hash array with tag attributes or string with image source (src) + * @return string HTML code + * @see html::tag() + */ + public static function img($attr = null) + { + if (is_string($attr)) { + $attr = array('src' => $attr); + } + return self::tag('img', $attr + array('alt' => ''), null, array_merge(self::$common_attrib, array('src','alt','width','height','border','usemap'))); + } + + /** + * Derrived method for link tags + * + * @param mixed Hash array with tag attributes or string with link location (href) + * @param string Link content + * @return string HTML code + * @see html::tag() + */ + public static function a($attr, $cont) + { + if (is_string($attr)) { + $attr = array('href' => $attr); + } + return self::tag('a', $attr, $cont, array_merge(self::$common_attrib, array('href','target','name','onclick','onmouseover','onmouseout'))); + } + + /** + * Derrived method for inline span tags + * + * @param mixed Hash array with tag attributes or string with class name + * @param string Tag content + * @return string HTML code + * @see html::tag() + */ + public static function span($attr, $cont) + { + if (is_string($attr)) { + $attr = array('class' => $attr); + } + return self::tag('span', $attr, $cont, self::$common_attrib); + } + + /** + * Derrived method for form element labels + * + * @param mixed Hash array with tag attributes or string with 'for' attrib + * @param string Tag content + * @return string HTML code + * @see html::tag() + */ + public static function label($attr, $cont) + { + if (is_string($attr)) { + $attr = array('for' => $attr); + } + return self::tag('label', $attr, $cont, array_merge(self::$common_attrib, array('for'))); + } + + /** + * Derrived method for line breaks + * + * @return string HTML code + * @see html::tag() + */ + public static function br() + { + return self::tag('br'); + } + + /** + * Create string with attributes + * + * @param array Associative arry with tag attributes + * @param array List of allowed attributes + * @return string Valid attribute string + */ + public static function attrib_string($attrib = array(), $allowed = null) + { + if (empty($attrib)) { + return ''; + } + + $allowed_f = array_flip((array)$allowed); + $attrib_arr = array(); + foreach ($attrib as $key => $value) { + // skip size if not numeric + if (($key=='size' && !is_numeric($value))) { + continue; + } + + // ignore "internal" or not allowed attributes + if ($key == 'nl' || ($allowed && !isset($allowed_f[$key])) || $value === null) { + continue; + } + + // skip empty eventhandlers + if (preg_match('/^on[a-z]+/', $key) && !$value) { + continue; + } + + // attributes with no value + if (in_array($key, array('checked', 'multiple', 'disabled', 'selected'))) { + if ($value) { + $attrib_arr[] = sprintf('%s="%s"', $key, $key); + } + } + else if ($key=='value') { + $attrib_arr[] = sprintf('%s="%s"', $key, Q($value, 'strict', false)); + } + else { + $attrib_arr[] = sprintf('%s="%s"', $key, Q($value)); + } + } + return count($attrib_arr) ? ' '.implode(' ', $attrib_arr) : ''; + } +} + +/** + * Class to create an HTML input field + * + * @package HTML + */ +class html_inputfield extends html +{ + protected $tagname = 'input'; + protected $type = 'text'; + + public function __construct($attrib = array()) + { + if (is_array($attrib)) { + $this->attrib = $attrib; + } + + if ($attrib['type']) { + $this->type = $attrib['type']; + } + + if ($attrib['newline']) { + $this->newline = true; + } + } + + /** + * Compose input tag + * + * @param string Field value + * @param array Additional attributes to override + * @return string HTML output + */ + public 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; + } + // set type + $this->attrib['type'] = $this->type; + return parent::show(); + } +} + +/** + * Class to create an HTML password field + * + * @package HTML + */ +class html_passwordfield extends html_inputfield +{ + protected $type = 'password'; +} + +/** + * Class to create an hidden HTML input field + * + * @package HTML + */ + +class html_hiddenfield extends html_inputfield +{ + protected $type = 'hidden'; + protected $fields_arr = array(); + protected $newline = true; + + /** + * Constructor + * + * @param array Named tag attributes + */ + public function __construct($attrib = null) + { + if (is_array($attrib)) { + $this->add($attrib); + } + } + + /** + * Add a hidden field to this instance + * + * @param array Named tag attributes + */ + public function add($attrib) + { + $this->fields_arr[] = $attrib; + } + + /** + * Create HTML code for the hidden fields + * + * @return string Final HTML code + */ + public function show() + { + $out = ''; + foreach ($this->fields_arr as $attrib) { + $out .= self::tag($this->tagname, array('type' => $this->type) + $attrib); + } + return $out; + } +} + +/** + * Class to create HTML radio buttons + * + * @package HTML + */ +class html_radiobutton extends html_inputfield +{ + protected $type = 'radio'; + + /** + * Get HTML code for this object + * + * @param string Value of the checked field + * @param array Additional attributes to override + * @return string HTML output + */ + public function show($value = '', $attrib = null) + { + // overwrite object attributes + if (is_array($attrib)) { + $this->attrib = array_merge($this->attrib, $attrib); + } + + // set value attribute + $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']); + + return parent::show(); + } +} + +/** + * Class to create HTML checkboxes + * + * @package HTML + */ +class html_checkbox extends html_inputfield +{ + protected $type = 'checkbox'; + + /** + * Get HTML code for this object + * + * @param string Value of the checked field + * @param array Additional attributes to override + * @return string HTML output + */ + public function show($value = '', $attrib = null) + { + // overwrite object attributes + if (is_array($attrib)) { + $this->attrib = array_merge($this->attrib, $attrib); + } + + // set value attribute + $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']); + + return parent::show(); + } +} + +/** + * Class to create an HTML textarea + * + * @package HTML + */ +class html_textarea extends html +{ + protected $tagname = 'textarea'; + protected $allowed_attrib = array('name','rows','cols','wrap','tabindex'); + + /** + * Get HTML code for this object + * + * @param string Textbox value + * @param array Additional attributes to override + * @return string HTML output + */ + public 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 (empty($value) && !empty($this->attrib['value'])) { + $value = $this->attrib['value']; + } + + // make shure we don't print the value attribute + if (isset($this->attrib['value'])) { + unset($this->attrib['value']); + } + + if (!empty($value) && !isset($this->attrib['mce_editable'])) { + $value = Q($value, 'strict', false); + } + return self::tag($this->tagname, $this->attrib, $value, array_merge(self::$common_attrib, $this->allowed_attrib)); + } +} + +/** + * Builder for HTML drop-down menus + * Syntax:

      + * // create instance. arguments are used to set attributes of select-tag
      + * $select = new html_select(array('name' => 'fieldname'));
      + *
      + * // add one option
      + * $select->add('Switzerland', 'CH');
      + *
      + * // add multiple options
      + * $select->add(array('Switzerland','Germany'), array('CH','DE'));
      + *
      + * // 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');
      + * 
      + * + * @package HTML + */ +class html_select extends html +{ + protected $tagname = 'select'; + protected $options = array(); + + /** + * Add a new option to this drop-down + * + * @param mixed Option name or array with option names + * @param mixed Option value or array with option values + */ + public function add($names, $values = null) + { + if (is_array($names)) { + foreach ($names as $i => $text) { + $this->options[] = array('text' => $text, 'value' => $values[$i]); + } + } + else { + $this->options[] = array('text' => $names, 'value' => $values); + } + } + + + /** + * Get HTML code for this object + * + * @param string Value of the selection option + * @param array Additional attributes to override + * @return string HTML output + */ + public function show($select = array(), $attrib = null) + { + // overwrite object attributes + if (is_array($attrib)) { + $this->attrib = array_merge($this->attrib, $attrib); + } + + $this->content = "\n"; + $select = (array)$select; + foreach ($this->options as $option) { + $attr = array( + 'value' => $option['value'], + 'selected' => (in_array($option['value'], $select, true) || + in_array($option['text'], $select, true)) ? 1 : null); + + $this->content .= self::tag('option', $attr, Q($option['text'])); + } + return parent::show(); + } +} + + +/** + * Class to build an HTML table + * + * @package HTML + */ +class html_table extends html +{ + protected $tagname = 'table'; + protected $allowed = array('id','class','style','width','summary','cellpadding','cellspacing','border'); + private $header = array(); + private $rows = array(); + private $rowindex = 0; + private $colindex = 0; + + + public function __construct($attrib = array()) + { + $this->attrib = array_merge($attrib, array('summary' => '', 'border' => 0)); + } + + /** + * Add a table cell + * + * @param array Cell attributes + * @param string Cell content + */ + public function add($attr, $cont) + { + if (is_string($attr)) { + $attr = array('class' => $attr); + } + + $cell = new stdClass; + $cell->attrib = $attr; + $cell->content = $cont; + + $this->rows[$this->rowindex]->cells[$this->colindex] = $cell; + $this->colindex++; + + if ($this->attrib['cols'] && $this->colindex == $this->attrib['cols']) { + $this->add_row(); + } + } + + /** + * Add a table header cell + * + * @param array Cell attributes + * @param string Cell content + */ + private function add_header($attr, $cont) + { + if (is_string($attr)) + $attr = array('class' => $attr); + + $cell = new stdClass; + $cell->attrib = $attr; + $cell->content = $cont; + $this->header[] = $cell; + } + + /** + * Jump to next row + * + * @param array Row attributes + */ + private function add_row($attr = array()) + { + $this->rowindex++; + $this->colindex = 0; + $this->rows[$this->rowindex] = new stdClass; + $this->rows[$this->rowindex]->attrib = $attr; + $this->rows[$this->rowindex]->cells = array(); + } + + + /** + * Build HTML output of the table data + * + * @param array Table attributes + * @return string The final table HTML code + */ + public function show($attr = array()) + { + $this->attrib = array_merge($this->attrib, $attr); + $thead = $tbody = ""; + + // include + if (!empty($this->header)) { + $rowcontent = ''; + foreach ($this->header as $c => $col) { + $rowcontent .= self::tag('th', $col->attrib, $col->content); + } + $thead = self::tag('thead', null, self::tag('tr', null, $rowcontent)); + } + + foreach ($this->rows as $r => $row) { + $rowcontent = ''; + foreach ($row->cells as $c => $col) { + $rowcontent .= self::tag('td', $col->attrib, $col->content); + } + + if ($r < $this->rowindex || count($row->cells)) { + $tbody .= self::tag('tr', $rows->attrib, $rowcontent); + } + } + + if ($this->attrib['rowsonly']) { + return $tbody; + } + + // add + $this->content = $thead . self::tag('tbody', null, $tbody); + + unset($this->attrib['cols'], $this->attrib['rowsonly']); + return parent::show(); + } +} + +?> \ No newline at end of file diff --git a/program/include/iniset.php b/program/include/iniset.php new file mode 100755 index 0000000..b718393 --- /dev/null +++ b/program/include/iniset.php @@ -0,0 +1,98 @@ + | + | Thomas Bruederli | + +-----------------------------------------------------------------------+ + + $Id: cache.inc 88 2005-12-03 16:54:12Z roundcube $ + +*/ + + +// application constants +define('RCMAIL_VERSION', '0.2-alpha'); +define('RCMAIL_CHARSET', 'UTF-8'); +define('JS_OBJECT_NAME', 'rcmail'); + +if (!defined('INSTALL_PATH')) { + define('INSTALL_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); +} + +// make sure path_separator is defined +if (!defined('PATH_SEPARATOR')) { + define('PATH_SEPARATOR', (eregi('win', PHP_OS) ? ';' : ':')); +} + +// RC include folders MUST be included FIRST to avoid other +// possible not compatible libraries (i.e PEAR) to be included +// instead the ones provided by RC +$include_path = INSTALL_PATH . PATH_SEPARATOR; +$include_path.= INSTALL_PATH . 'program' . PATH_SEPARATOR; +$include_path.= INSTALL_PATH . 'program/lib' . PATH_SEPARATOR; +$include_path.= INSTALL_PATH . 'program/include' . PATH_SEPARATOR; +$include_path.= ini_get('include_path'); + +if (set_include_path($include_path) === false) { + die('Fatal error: ini_set/set_include_path does not work.'); +} + +ini_set('session.name', 'roundcube_sessid'); +ini_set('session.use_cookies', 1); +ini_set('session.gc_maxlifetime', 21600); +ini_set('session.gc_divisor', 500); +ini_set('error_reporting', E_ALL&~E_NOTICE); +set_magic_quotes_runtime(0); + +// increase maximum execution time for php scripts +// (does not work in safe mode) +if (!ini_get('safe_mode')) { + set_time_limit(120); +} + +/** + * Use PHP5 autoload for dynamic class loading + * + * @todo Make Zend, PEAR etc play with this + */ +function __autoload($classname) +{ + $filename = preg_replace( + array('/MDB2_(.+)/', '/Mail_(.+)/', '/^html_.+/', '/^utf8$/'), + array('MDB2/\\1', 'Mail/\\1', 'html', 'utf8.class'), + $classname + ); + include_once $filename. '.php'; +} + +/** + * Local callback function for PEAR errors + */ +function rcube_pear_error($err) +{ + error_log(sprintf("%s (%s): %s", + $err->getMessage(), + $err->getCode(), + $err->getUserinfo()), 0); +} + +// include global functions +require_once 'include/bugs.inc'; +require_once 'include/main.inc'; +require_once 'include/rcube_shared.inc'; + + +// set PEAR error handling (will also load the PEAR main class) +PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error'); + diff --git a/program/include/main.inc b/program/include/main.inc index 446780c..c6b4168 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: main.inc 1255 2008-04-05 12:49:21Z thomasb $ + $Id: main.inc 1459 2008-05-30 19:55:28Z alec $ */ @@ -27,9 +27,7 @@ */ require_once('lib/utf7.inc'); -require_once('include/rcube_user.inc'); require_once('include/rcube_shared.inc'); -require_once('include/rcmail_template.inc'); // define constannts for input reading define('RCUBE_INPUT_GET', 0x0101); @@ -37,313 +35,6 @@ define('RCUBE_INPUT_POST', 0x0102); define('RCUBE_INPUT_GPC', 0x0103); -/** - * Initial startup function - * to register session, create database and imap connections - * - * @param string Current task - */ -function rcmail_startup($task='mail') - { - global $sess_id, $sess_user_lang; - global $CONFIG, $INSTALL_PATH, $BROWSER, $OUTPUT, $_SESSION, $IMAP, $DB, $USER; - - // check client - $BROWSER = rcube_browser(); - - // load configuration - $CONFIG = rcmail_load_config(); - - // set session domain - if (isset($CONFIG['session_domain']) && !empty($CONFIG['session_domain'])) { - ini_set('session.cookie_domain', $CONFIG['session_domain']); - } - - // set session garbage collecting time according to session_lifetime - if (!empty($CONFIG['session_lifetime'])) - ini_set('session.gc_maxlifetime', ($CONFIG['session_lifetime']) * 120); - - // prepare DB connection - $dbwrapper = empty($CONFIG['db_backend']) ? 'db' : $CONFIG['db_backend']; - $dbclass = "rcube_" . $dbwrapper; - require_once("include/$dbclass.inc"); - - $DB = new $dbclass($CONFIG['db_dsnw'], $CONFIG['db_dsnr'], $CONFIG['db_persistent']); - $DB->sqlite_initials = $INSTALL_PATH.'SQL/sqlite.initial.sql'; - $DB->set_debug((bool)$CONFIG['sql_debug']); - $DB->db_connect('w'); - - // use database for storing session data - include_once('include/session.inc'); - - // init session - session_start(); - $sess_id = session_id(); - - // create session and set session vars - if (!isset($_SESSION['auth_time'])) - { - $_SESSION['user_lang'] = rcube_language_prop($CONFIG['locale_string']); - $_SESSION['auth_time'] = time(); - $_SESSION['temp'] = true; - } - - // set session vars global - $sess_user_lang = rcube_language_prop($_SESSION['user_lang']); - - // create user object - $USER = new rcube_user($_SESSION['user_id']); - - // overwrite config with user preferences - $CONFIG = array_merge($CONFIG, (array)$USER->get_prefs()); - - - // reset some session parameters when changing task - if ($_SESSION['task'] != $task) - unset($_SESSION['page']); - - // set current task to session - $_SESSION['task'] = $task; - - // create IMAP object - if ($task=='mail') - rcmail_imap_init(); - - - // set localization - if ($CONFIG['locale_string']) - setlocale(LC_ALL, $CONFIG['locale_string']); - else if ($sess_user_lang) - setlocale(LC_ALL, $sess_user_lang); - - - register_shutdown_function('rcmail_shutdown'); - } - - -/** - * Load roundcube configuration array - * - * @return array Named configuration parameters - */ -function rcmail_load_config() - { - global $INSTALL_PATH; - - // load config file - include_once('config/main.inc.php'); - $conf = is_array($rcmail_config) ? $rcmail_config : array(); - - // load host-specific configuration - rcmail_load_host_config($conf); - - $conf['skin_path'] = $conf['skin_path'] ? unslashify($conf['skin_path']) : 'skins/default'; - - // load db conf - include_once('config/db.inc.php'); - $conf = array_merge($conf, $rcmail_config); - - if (empty($conf['log_dir'])) - $conf['log_dir'] = $INSTALL_PATH.'logs'; - else - $conf['log_dir'] = unslashify($conf['log_dir']); - - // set PHP error logging according to config - if ($conf['debug_level'] & 1) - { - ini_set('log_errors', 1); - ini_set('error_log', $conf['log_dir'].'/errors'); - } - if ($conf['debug_level'] & 4) - ini_set('display_errors', 1); - else - ini_set('display_errors', 0); - - return $conf; - } - - -/** - * Load a host-specific config file if configured - * This will merge the host specific configuration with the given one - * - * @param array Global configuration parameters - */ -function rcmail_load_host_config(&$config) - { - $fname = NULL; - - if (is_array($config['include_host_config'])) - $fname = $config['include_host_config'][$_SERVER['HTTP_HOST']]; - else if (!empty($config['include_host_config'])) - $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $_SERVER['HTTP_HOST']) . '.inc.php'; - - if ($fname && is_file('config/'.$fname)) - { - include('config/'.$fname); - $config = array_merge($config, $rcmail_config); - } - } - - -/** - * Create unique authorization hash - * - * @param string Session ID - * @param int Timestamp - * @return string The generated auth hash - */ -function rcmail_auth_hash($sess_id, $ts) - { - global $CONFIG; - - $auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s', - $sess_id, - $ts, - $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***', - $_SERVER['HTTP_USER_AGENT']); - - if (function_exists('sha1')) - return sha1($auth_string); - else - return md5($auth_string); - } - - -/** - * Check the auth hash sent by the client against the local session credentials - * - * @return boolean True if valid, False if not - */ -function rcmail_authenticate_session() - { - global $CONFIG, $SESS_CLIENT_IP, $SESS_CHANGED; - - // advanced session authentication - if ($CONFIG['double_auth']) - { - $now = time(); - $valid = ($_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['auth_time']) || - $_COOKIE['sessauth'] == rcmail_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; - setcookie('sessauth', rcmail_auth_hash(session_id(), $now)); - } - } - else - $valid = $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] == $SESS_CLIENT_IP : true; - - // check session filetime - if (!empty($CONFIG['session_lifetime']) && isset($SESS_CHANGED) - && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < time()) - $valid = false; - - return $valid; - } - - -/** - * Create global IMAP object and connect to server - * - * @param boolean True if connection should be established - */ -function rcmail_imap_init($connect=FALSE) - { - global $CONFIG, $DB, $IMAP, $OUTPUT; - - $IMAP = new rcube_imap($DB); - $IMAP->debug_level = $CONFIG['debug_level']; - $IMAP->skip_deleted = $CONFIG['skip_deleted']; - - - // connect with stored session data - if ($connect) - { - if (!($conn = $IMAP->connect($_SESSION['imap_host'], $_SESSION['username'], decrypt_passwd($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl']))) - $OUTPUT->show_message('imaperror', 'error'); - - rcmail_set_imap_prop(); - } - - // enable caching of imap data - if ($CONFIG['enable_caching']===TRUE) - $IMAP->set_caching(TRUE); - - // set pagesize from config - if (isset($CONFIG['pagesize'])) - $IMAP->set_pagesize($CONFIG['pagesize']); - } - - -/** - * Set root dir and last stored mailbox - * This must be done AFTER connecting to the server! - */ -function rcmail_set_imap_prop() - { - global $CONFIG, $IMAP; - - if (!empty($CONFIG['default_charset'])) - $IMAP->set_charset($CONFIG['default_charset']); - - // set root dir from config - if (!empty($CONFIG['imap_root'])) - $IMAP->set_rootdir($CONFIG['imap_root']); - - if (is_array($CONFIG['default_imap_folders'])) - $IMAP->set_default_mailboxes($CONFIG['default_imap_folders']); - - if (!empty($_SESSION['mbox'])) - $IMAP->set_mailbox($_SESSION['mbox']); - if (isset($_SESSION['page'])) - $IMAP->set_page($_SESSION['page']); - } - - -/** - * Do these things on script shutdown - */ -function rcmail_shutdown() - { - global $IMAP, $CONTACTS; - - if (is_object($IMAP)) - { - $IMAP->close(); - $IMAP->write_cache(); - } - - if (is_object($CONTACTS)) - $CONTACTS->close(); - - // before closing the database connection, write session data - session_write_close(); - } - - -/** - * Destroy session data and remove cookie - */ -function rcmail_kill_session() - { - global $USER; - - if ((isset($_SESSION['sort_col']) && $_SESSION['sort_col']!=$a_user_prefs['message_sort_col']) || - (isset($_SESSION['sort_order']) && $_SESSION['sort_order']!=$a_user_prefs['message_sort_order'])) - { - $a_user_prefs = array('message_sort_col' => $_SESSION['sort_col'], 'message_sort_order' => $_SESSION['sort_order']); - $USER->save_prefs($a_user_prefs); - } - - $_SESSION = array('user_lang' => $GLOBALS['sess_user_lang'], 'auth_time' => time(), 'temp' => true); - setcookie('sessauth', '-del-', time()-60); - $USER->reset(); - } - /** * Return correct name for a specific database table @@ -354,319 +45,59 @@ function rcmail_kill_session() function get_table_name($table) { global $CONFIG; - + // return table name if configured $config_key = 'db_table_'.$table; if (strlen($CONFIG[$config_key])) return $CONFIG[$config_key]; - + return $table; } /** * Return correct name for a specific database sequence - * (used for Postres only) + * (used for Postgres only) * * @param string Secuence name * @return string Translated sequence name */ function get_sequence_name($sequence) { - global $CONFIG; - // return table name if configured $config_key = 'db_sequence_'.$sequence; + $opt = rcmail::get_instance()->config->get($config_key); - if (strlen($CONFIG[$config_key])) - return $CONFIG[$config_key]; - - return $sequence; - } - - -/** - * Check the given string and returns language properties - * - * @param string Language code - * @param string Peropert name - * @return string Property value - */ -function rcube_language_prop($lang, $prop='lang') - { - global $INSTALL_PATH; - static $rcube_languages, $rcube_language_aliases, $rcube_charsets; - - if (empty($rcube_languages)) - @include($INSTALL_PATH.'program/localization/index.inc'); - - // check if we have an alias for that language - if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang])) - $lang = $rcube_language_aliases[$lang]; - - // try the first two chars - if (!isset($rcube_languages[$lang]) && strlen($lang)>2) + if (!empty($opt)) { - $lang = substr($lang, 0, 2); - $lang = rcube_language_prop($lang); - } - - if (!isset($rcube_languages[$lang])) - $lang = 'en_US'; - - // language has special charset configured - if (isset($rcube_charsets[$lang])) - $charset = $rcube_charsets[$lang]; - else - $charset = 'UTF-8'; - - - if ($prop=='charset') - return $charset; - else - return $lang; - } - - -/** - * Init output object for GUI and add common scripts. - * This will instantiate a rcmail_template object and set - * environment vars according to the current session and configuration - */ -function rcmail_load_gui() - { - global $CONFIG, $OUTPUT, $sess_user_lang; - - // init output page - $OUTPUT = new rcmail_template($CONFIG, $GLOBALS['_task']); - $OUTPUT->set_env('comm_path', $GLOBALS['COMM_PATH']); - - if (is_array($CONFIG['javascript_config'])) - { - foreach ($CONFIG['javascript_config'] as $js_config_var) - $OUTPUT->set_env($js_config_var, $CONFIG[$js_config_var]); - } - - if (!empty($GLOBALS['_framed'])) - $OUTPUT->set_env('framed', true); + $db = &rcmail::get_instance()->db; - // set locale setting - rcmail_set_locale($sess_user_lang); - - // set user-selected charset - if (!empty($CONFIG['charset'])) - $OUTPUT->set_charset($CONFIG['charset']); - - // register common UI objects - $OUTPUT->add_handlers(array( - 'loginform' => 'rcmail_login_form', - 'username' => 'rcmail_current_username', - 'message' => 'rcmail_message_container', - 'charsetselector' => 'rcmail_charset_selector', - )); - - // add some basic label to client - if (!$OUTPUT->ajax_call) - rcube_add_label('loading', 'movingmessage'); - } - - -/** - * Set localization charset based on the given language. - * This also creates a global property for mbstring usage. - */ -function rcmail_set_locale($lang) - { - global $OUTPUT, $MBSTRING; - static $s_mbstring_loaded = NULL; - - // settings for mbstring module (by Tadashi Jokagi) - if (is_null($s_mbstring_loaded)) - $MBSTRING = $s_mbstring_loaded = extension_loaded("mbstring"); - else - $MBSTRING = $s_mbstring_loaded = FALSE; - - if ($MBSTRING) - mb_internal_encoding(RCMAIL_CHARSET); - - $OUTPUT->set_charset(rcube_language_prop($lang, 'charset')); - } - - -/** - * Auto-select IMAP host based on the posted login information - * - * @return string Selected IMAP host - */ -function rcmail_autoselect_host() - { - global $CONFIG; - - $host = isset($_POST['_host']) ? get_input_value('_host', RCUBE_INPUT_POST) : $CONFIG['default_host']; - if (is_array($host)) - { - list($user, $domain) = explode('@', get_input_value('_user', RCUBE_INPUT_POST)); - if (!empty($domain)) + if($db->db_provider=='pgsql') // just for sure { - foreach ($host as $imap_host => $mail_domains) - if (is_array($mail_domains) && in_array($domain, $mail_domains)) - { - $host = $imap_host; - break; - } - } - - // take the first entry if $host is still an array - if (is_array($host)) - $host = array_shift($host); - } + $db->db_handle->setOption('disable_smart_seqname', true); + $db->db_handle->setOption('seqname_format', '%s'); + } - return $host; + return $CONFIG[$opt]; + } + + return $sequence; } /** - * Perfom login to the IMAP server and to the webmail service. - * This will also create a new user entry if auto_create_user is configured. + * Get localized text in the desired language + * It's a global wrapper for rcmail::gettext() * - * @param string IMAP user name - * @param string IMAP password - * @param string IMAP host - * @return boolean True on success, False on failure + * @param mixed Named parameters array or label name + * @return string Localized text + * @see rcmail::gettext() */ -function rcmail_login($user, $pass, $host=NULL) - { - global $CONFIG, $IMAP, $DB, $USER, $sess_user_lang; - $user_id = NULL; - - if (!$host) - $host = $CONFIG['default_host']; - - // Validate that selected host is in the list of configured hosts - if (is_array($CONFIG['default_host'])) - { - $allowed = FALSE; - foreach ($CONFIG['default_host'] as $key => $host_allowed) - { - if (!is_numeric($key)) - $host_allowed = $key; - if ($host == $host_allowed) - { - $allowed = TRUE; - break; - } - } - if (!$allowed) - return FALSE; - } - else if (!empty($CONFIG['default_host']) && $host != $CONFIG['default_host']) - return FALSE; - - // parse $host URL - $a_host = parse_url($host); - if ($a_host['host']) - { - $host = $a_host['host']; - $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; - $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : $CONFIG['default_port']); - } - else - $imap_port = $CONFIG['default_port']; - - - /* Modify username with domain if required - Inspired by Marco - */ - // Check if we need to add domain - if (!empty($CONFIG['username_domain']) && !strpos($user, '@')) - { - if (is_array($CONFIG['username_domain']) && isset($CONFIG['username_domain'][$host])) - $user .= '@'.$CONFIG['username_domain'][$host]; - else if (is_string($CONFIG['username_domain'])) - $user .= '@'.$CONFIG['username_domain']; - } - - // try to resolve email address from virtuser table - if (!empty($CONFIG['virtuser_file']) && strpos($user, '@')) - $user = rcube_user::email2user($user); - - // lowercase username if it's an e-mail address (#1484473) - if (strpos($user, '@')) - $user = strtolower($user); - - // query if user already registered - if ($existing = rcube_user::query($user, $host)) - $USER = $existing; - - // user already registered -> overwrite username - if ($USER->ID) - { - $user_id = $USER->ID; - $user = $USER->data['username']; - } - - // exit if IMAP login failed - if (!($imap_login = $IMAP->connect($host, $user, $pass, $imap_port, $imap_ssl))) - return false; - - // user already registered - if ($USER->ID) - { - // get user prefs - $CONFIG = array_merge($CONFIG, (array)$USER->get_prefs()); - - // set user specific language - if (!empty($USER->data['language'])) - $sess_user_lang = $_SESSION['user_lang'] = $USER->data['language']; - - // update user's record - $USER->touch(); - } - // create new system user - else if ($CONFIG['auto_create_user']) - { - if ($created = rcube_user::create($user, $host)) - { - $USER = $created; - - // get existing mailboxes - $a_mailboxes = $IMAP->list_mailboxes(); - } - } - else - { - raise_error(array( - 'code' => 600, - 'type' => 'php', - 'file' => "config/main.inc.php", - 'message' => "Acces denied for new user $user. 'auto_create_user' is disabled" - ), true, false); - } - - if ($USER->ID) - { - $_SESSION['user_id'] = $USER->ID; - $_SESSION['username'] = $USER->data['username']; - $_SESSION['imap_host'] = $host; - $_SESSION['imap_port'] = $imap_port; - $_SESSION['imap_ssl'] = $imap_ssl; - $_SESSION['user_lang'] = $sess_user_lang; - $_SESSION['password'] = encrypt_passwd($pass); - $_SESSION['login_time'] = mktime(); - - // force reloading complete list of subscribed mailboxes - rcmail_set_imap_prop(); - $IMAP->clear_cache('mailboxes'); - - if ($CONFIG['create_default_folders']) - $IMAP->create_default_folders(); - - return TRUE; - } - - return FALSE; - } +function rcube_label($p) +{ + return rcmail::get_instance()->gettext($p); +} /** @@ -721,9 +152,9 @@ function rcmail_findinvirtual($pattern) */ function rcmail_overwrite_action($action) { - global $OUTPUT; - $GLOBALS['_action'] = $action; - $OUTPUT->set_env('action', $action); + $app = rcmail::get_instance(); + $app->action = $action; + $app->output->set_env('action', $action); } @@ -737,12 +168,13 @@ function rcmail_overwrite_action($action) */ function rcmail_url($action, $p=array(), $task=null) { - global $MAIN_TASKS, $COMM_PATH; + $app = rcmail::get_instance(); + $qstring = ''; - $base = $COMM_PATH; + $base = $app->comm_path; - if ($task && in_array($task, $MAIN_TASKS)) - $base = ereg_replace('_task=[a-z]+', '_task='.$task, $COMM_PATH); + if ($task && in_array($task, rcmail::$main_tasks)) + $base = ereg_replace('_task=[a-z]+', '_task='.$task, $app->comm_path); if (is_array($p)) foreach ($p as $key => $val) @@ -752,126 +184,9 @@ function rcmail_url($action, $p=array(), $task=null) } -// @deprecated -function show_message($message, $type='notice', $vars=NULL) - { - global $OUTPUT; - $OUTPUT->show_message($message, $type, $vars); - } - - -/** - * Encrypt IMAP password using DES encryption - * - * @param string Password to encrypt - * @return string Encryprted string - */ -function encrypt_passwd($pass) -{ - if (function_exists('mcrypt_module_open') && ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_ECB, ""))) { - $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND); - mcrypt_generic_init($td, get_des_key(), $iv); - $cypher = mcrypt_generic($td, $pass); - mcrypt_generic_deinit($td); - mcrypt_module_close($td); - } - else if (function_exists('des')) { - $cypher = des(get_des_key(), $pass, 1, 0, NULL); - } - else { - $cypher = $pass; - - raise_error(array( - 'code' => 500, - 'type' => 'php', - 'file' => __FILE__, - 'message' => "Could not convert encrypt password. Make sure Mcrypt is installed or lib/des.inc is available" - ), true, false); - } - - return base64_encode($cypher); -} - - -/** - * Decrypt IMAP password using DES encryption - * - * @param string Encrypted password - * @return string Plain password - */ -function decrypt_passwd($cypher) -{ - if (function_exists('mcrypt_module_open') && ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_ECB, ""))) { - $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND); - mcrypt_generic_init($td, get_des_key(), $iv); - $pass = mdecrypt_generic($td, base64_decode($cypher)); - mcrypt_generic_deinit($td); - mcrypt_module_close($td); - } - else if (function_exists('des')) { - $pass = des(get_des_key(), base64_decode($cypher), 0, 0, NULL); - } - else { - $pass = base64_decode($cypher); - } - - return preg_replace('/\x00/', '', $pass); - } - - -/** - * Return a 24 byte key for the DES encryption - * - * @return string DES encryption key - */ -function get_des_key() - { - $key = !empty($GLOBALS['CONFIG']['des_key']) ? $GLOBALS['CONFIG']['des_key'] : 'rcmail?24BitPwDkeyF**ECB'; - $len = strlen($key); - - // make sure the key is exactly 24 chars long - if ($len<24) - $key .= str_repeat('_', 24-$len); - else if ($len>24) - substr($key, 0, 24); - - return $key; - } - - -/** - * Read directory program/localization and return a list of available languages - * - * @return array List of available localizations - */ -function rcube_list_languages() - { - global $CONFIG, $INSTALL_PATH; - static $sa_languages = array(); - - if (!sizeof($sa_languages)) - { - @include($INSTALL_PATH.'program/localization/index.inc'); - - if ($dh = @opendir($INSTALL_PATH.'program/localization')) - { - while (($name = readdir($dh)) !== false) - { - if ($name{0}=='.' || !is_dir($INSTALL_PATH.'program/localization/'.$name)) - continue; - - if ($label = $rcube_languages[$name]) - $sa_languages[$name] = $label ? $label : $name; - } - closedir($dh); - } - } - return $sa_languages; - } - - /** * Add a localized label to the client environment + * @deprecated */ function rcube_add_label() { @@ -879,7 +194,7 @@ function rcube_add_label() $arg_list = func_get_args(); foreach ($arg_list as $i => $name) - $OUTPUT->command('add_label', $name, rcube_label($name)); + $OUTPUT->add_label($name); } @@ -939,8 +254,7 @@ function rcmail_message_cache_gc() */ function rcube_charset_convert($str, $from, $to=NULL) { - global $MBSTRING; - static $convert_warning = false; + static $mbstring_loaded = null, $convert_warning = false; $from = strtoupper($from); $to = $to==NULL ? strtoupper(RCMAIL_CHARSET) : strtoupper($to); @@ -961,11 +275,21 @@ function rcube_charset_convert($str, $from, $to=NULL) if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7') { $aliases['GB2312'] = 'GB18030'; - return iconv(($aliases[$from] ? $aliases[$from] : $from), ($aliases[$to] ? $aliases[$to] : $to) . "//IGNORE", $str); + $_iconv = iconv(($aliases[$from] ? $aliases[$from] : $from), ($aliases[$to] ? $aliases[$to] : $to) . "//IGNORE", $str); + if ($_iconv !== false) + { + return $_iconv; + } } - // convert charset using mbstring module - if ($MBSTRING) + // settings for mbstring module (by Tadashi Jokagi) + if (is_null($mbstring_loaded)) { + if ($mbstring_loaded = extension_loaded("mbstring")) + mb_internal_encoding(RCMAIL_CHARSET); + } + + // convert charset using mbstring module + if ($mbstring_loaded) { $aliases['UTF-7'] = 'UTF7-IMAP'; $aliases['WINDOWS-1257'] = 'ISO-8859-13'; @@ -1034,9 +358,16 @@ function rcube_charset_convert($str, $from, $to=NULL) */ function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE) { - global $OUTPUT_TYPE, $OUTPUT; - static $html_encode_arr, $js_rep_table, $xml_rep_table; - + global $OUTPUT; + static $html_encode_arr = false; + static $js_rep_table = false; + static $xml_rep_table = false; + + $charset = $OUTPUT->get_charset(); + $is_iso_8859_1 = false; + if ($charset == 'ISO-8859-1') { + $is_iso_8859_1 = true; + } if (!$enctype) $enctype = $GLOBALS['OUTPUT_TYPE']; @@ -1077,7 +408,7 @@ function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE) return rawurlencode($str); // if the replace tables for XML and JS are not yet defined - if (!$js_rep_table) + if ($js_rep_table===false) { $js_rep_table = $xml_rep_table = array(); $xml_rep_table['&'] = '&'; @@ -1086,7 +417,7 @@ function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE) { $xml_rep_table[Chr($c)] = "&#$c;"; - if ($OUTPUT->get_charset()=='ISO-8859-1') + if ($is_iso_8859_1) $js_rep_table[Chr($c)] = sprintf("\\u%04x", $c); } @@ -1100,10 +431,10 @@ function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE) // encode for javascript use if ($enctype=='js') { - if ($OUTPUT->get_charset()!='UTF-8') - $str = rcube_charset_convert($str, RCMAIL_CHARSET, $OUTPUT->get_charset()); + if ($charset!='UTF-8') + $str = rcube_charset_convert($str, RCMAIL_CHARSET,$charset); - return preg_replace(array("/\r?\n/", "/\r/"), array('\n', '\n'), addslashes(strtr($str, $js_rep_table))); + return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), addslashes(strtr($str, $js_rep_table))); } // no encoding given -> return original string @@ -1228,16 +559,6 @@ function template_exists($name) } -/** - * Wrapper for rcmail_template::parse() - * @deprecated - */ -function parse_template($name='main', $exit=true) - { - $GLOBALS['OUTPUT']->parse($name, $exit); - } - - /** * Create a HTML table based on the given data * @@ -1290,7 +611,7 @@ function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col) { $zebra_class = $c%2 ? 'even' : 'odd'; - $table .= sprintf(''."\n", $row_data[$id_col]); + $table .= sprintf(''."\n", $row_data[$id_col]); // format each col foreach ($a_show_cols as $col) @@ -1328,15 +649,15 @@ function rcmail_get_edit_field($col, $value, $attrib, $type='text') if ($type=='checkbox') { $attrib['value'] = '1'; - $input = new checkbox($attrib); + $input = new html_checkbox($attrib); } else if ($type=='textarea') { $attrib['cols'] = $attrib['size']; - $input = new textarea($attrib); + $input = new html_textarea($attrib); } else - $input = new textfield($attrib); + $input = new html_inputfield($attrib); // use value from post if (!empty($_POST[$fname])) @@ -1468,12 +789,14 @@ function create_attrib_string($attrib, $allowed_attribs=array('id', 'class', 'st function parse_attrib_string($str) { $attrib = array(); - preg_match_all('/\s*([-_a-z]+)=(["\'])([^"]+)\2/Ui', stripslashes($str), $regs, PREG_SET_ORDER); + preg_match_all('/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]+)\2|(\S+?))/Ui', stripslashes($str), $regs, PREG_SET_ORDER); // convert attributes to an associative array (name => value) if ($regs) foreach ($regs as $attr) - $attrib[strtolower($attr[1])] = $attr[3]; + { + $attrib[strtolower($attr[1])] = $attr[3] . $attr[4]; + } return $attrib; } @@ -1489,15 +812,25 @@ function parse_attrib_string($str) */ function format_date($date, $format=NULL) { - global $CONFIG, $sess_user_lang; + global $CONFIG; $ts = NULL; - + if (is_numeric($date)) $ts = $date; else if (!empty($date)) - $ts = @strtotime($date); - + { + while (($ts = @strtotime($date))===false) + { + // if we have a date in non-rfc format + // remove token from the end and try again + $d = explode(' ', $date); + array_pop($d); + if (!$d) break; + $date = implode(' ', $d); + } + } + if (empty($ts)) return ''; @@ -1549,7 +882,7 @@ function format_date($date, $format=NULL) $out .= rcube_label(strtolower(date('M', $timestamp))); // month name (long) else if ($format{$i}=='F') - $out .= rcube_label(strtolower(date('F', $timestamp))); + $out .= rcube_label('long'.strtolower(date('M', $timestamp))); else $out .= date($format{$i}, $timestamp); } @@ -1593,7 +926,7 @@ function console($msg) if (!($GLOBALS['CONFIG']['debug_level'] & 4)) write_log('console', $msg); - else if ($GLOBALS['REMOTE_REQUEST']) + else if ($GLOBALS['OUTPUT']->ajax_call) print "/*\n $msg \n*/\n"; else { @@ -1608,12 +941,12 @@ function console($msg) * Append a line to a logfile in the logs directory. * Date will be added automatically to the line. * - * @param $name Name of logfile - * @param $line Line to append + * @param $name name of log file + * @param line Line to append */ function write_log($name, $line) { - global $CONFIG, $INSTALL_PATH; + global $CONFIG; if (!is_string($line)) $line = var_export($line, true); @@ -1623,7 +956,7 @@ function write_log($name, $line) $line); if (empty($CONFIG['log_dir'])) - $CONFIG['log_dir'] = $INSTALL_PATH.'logs'; + $CONFIG['log_dir'] = INSTALL_PATH.'logs'; // try to open specific log file for writing if ($fp = @fopen($CONFIG['log_dir'].'/'.$name, 'a')) @@ -1811,7 +1144,7 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, $maxlength, $ $class_name = 'junk'; $js_name = htmlspecialchars(JQ($folder['id'])); - $out .= sprintf('
    • $folder['id']))), JS_OBJECT_NAME, @@ -1848,7 +1180,7 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, $maxlength, $ * Return html for a flat list
    • '); - - $this->write(trim($this->parse_with_globals($output)), $skin_path); - - if ($exit) - exit; - } - - - /** - * Return executable javascript code for all registered commands - * @access private - */ - function get_js_commands() - { - $out = ''; - if (!$this->framed && !empty($this->js_env)) - $out .= ($this->ajax_call ? 'this' : JS_OBJECT_NAME) . '.set_env('.json_serialize($this->js_env).");\n"; - - // add command to set page title - if ($this->ajax_call && !empty($this->pagetitle)) - $out .= sprintf( - "this.set_pagetitle('%s');\n", - JQ((!empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '') . $this->pagetitle) - ); - - foreach ($this->js_commands as $i => $args) - { - $method = array_shift($args); - foreach ($args as $i => $arg) - $args[$i] = json_serialize($arg); - - $parent = $this->framed || preg_match('/^parent\./', $method); - $out .= sprintf( - "%s.%s(%s);\n", - $this->ajax_call ? 'this' : ($parent ? 'parent.' : '') . JS_OBJECT_NAME, - preg_replace('/^parent\./', '', $method), - join(',', $args)); - } - - - - return $out; - } - - /** - * Make URLs starting with a slash point to skin directory - * @access private - */ - function abs_url($str) - { - return preg_replace('/^\//', $this->config['skin_path'].'/', $str); - } - - - - /***** Template parsing methods *****/ - - /** - * Replace all strings ($varname) - * with the content of the according global variable. - * @access private - */ - function parse_with_globals($input) - { - $GLOBALS['__comm_path'] = Q($GLOBALS['COMM_PATH']); - return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input); - } - - - /** - * Parse for conditional tags - * @access private - */ - function parse_conditions($input) - { - if (($matches = preg_split('/]+)>/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE)) && count($matches)==4) - { - if (preg_match('/^(else|endif)$/i', $matches[1])) - return $matches[0] . $this->parse_conditions($matches[3]); - else - { - $attrib = parse_attrib_string($matches[2]); - if (isset($attrib['condition'])) - { - $condmet = $this->check_condition($attrib['condition']); - $submatches = preg_split('/]+)>/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE); - - if ($condmet) - $result = $submatches[0] . ($submatches[1] != 'endif' ? preg_replace('/.*]+>/Uis', '', $submatches[3], 1) : $submatches[3]); - else - $result = "" . $submatches[3]; - - return $matches[0] . $this->parse_conditions($result); - } - else - { - raise_error(array('code' => 500, 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__, - 'message' => "Unable to parse conditional tag " . $matches[2]), TRUE, FALSE); - } - } - } - - return $input; - } - - - /** - * Determines if a given condition is met - * - * @return True if condition is valid, False is not - * @access private - */ - function check_condition($condition) - { - $condition = preg_replace( - array('/session:([a-z0-9_]+)/i', '/config:([a-z0-9_]+)/i', '/env:([a-z0-9_]+)/i', '/request:([a-z0-9_]+)/ie'), - array("\$_SESSION['\\1']", "\$this->config['\\1']", "\$this->env['\\1']", "get_input_value('\\1', RCUBE_INPUT_GPC)"), - $condition); - - return @eval("return (".$condition.");"); - } - - - /** - * Search for special tags in input and replace them - * with the appropriate content - * - * @param string Input string to parse - * @return Altered input string - * @access private - */ - function parse_xml($input) - { - return preg_replace('/]+)>/Uie', "\$this->xml_command('\\1', '\\2')", $input); - } - - - /** - * Convert a xml command tag into real content - * - * @param string Tag command: object,button,label, etc. - * @param string Attribute string - * @return Tag/Object content string - * @access private - */ - function xml_command($command, $str_attrib, $add_attrib=array()) - { - $command = strtolower($command); - $attrib = parse_attrib_string($str_attrib) + $add_attrib; - - // empty output if required condition is not met - if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) - return ''; - - // execute command - switch ($command) - { - // return a button - case 'button': - return $this->button($attrib); - break; - - // show a label - case 'label': - if ($attrib['name'] || $attrib['command']) - return Q(rcube_label($attrib + array('vars' => array('product' => $this->config['product_name'])))); - break; - - // include a file - case 'include': - $path = realpath($this->config['skin_path'].$attrib['file']); - if (filesize($path)) - { - if ($this->config['skin_include_php']) - $incl = $this->include_php($path); - else if ($fp = @fopen($path, 'r')) - { - $incl = fread($fp, filesize($path)); - fclose($fp); - } - return $this->parse_xml($incl); - } - break; - - // return code for a specific application object - case 'object': - $object = strtolower($attrib['name']); - - // execute object handler function - if ($this->object_handlers[$object] && function_exists($this->object_handlers[$object])) - return call_user_func($this->object_handlers[$object], $attrib); - - else if ($object=='productname') - { - $name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail'; - return Q($name); - } - else if ($object=='version') - { - return (string)RCMAIL_VERSION; - } - else if ($object=='pagetitle') - { - $task = $this->task; - $title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : ''; - - if (!empty($this->pagetitle)) - $title .= $this->pagetitle; - else if ($task == 'login') - $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name']))); - else - $title .= ucfirst($task); - - return Q($title); - } - - break; - - // return variable - case 'var': - $var = explode(':', $attrib['name']); - $name = $var[1]; - $value = ''; - - switch ($var[0]) - { - case 'env': - $value = $this->env[$name]; - break; - case 'config': - $value = $this->config[$name]; - if (is_array($value) && $value[$_SESSION['imap_host']]) - $value = $value[$_SESSION['imap_host']]; - break; - case 'request': - $value = get_input_value($name, RCUBE_INPUT_GPC); - break; - case 'session': - $value = $_SESSION[$name]; - break; - } - - if (is_array($value)) - $value = join(", ", $value); - - return Q($value); - } - - return ''; - } - - - /** - * Include a specific file and return it's contents - * - * @param string File path - * @return string Contents of the processed file - */ - function include_php($file) - { - ob_start(); - @include($file); - $out = ob_get_contents(); - ob_end_clean(); - - return $out; - } - - - /** - * Create and register a button - * - * @param array Button attributes - * @return HTML button - * @access private - */ - function button($attrib) - { - global $CONFIG, $OUTPUT, $BROWSER, $MAIN_TASKS; - static $sa_buttons = array(); - static $s_button_count = 100; - - // these commands can be called directly via url - $a_static_commands = array('compose', 'list'); - - $skin_path = $this->config['skin_path']; - - if (!($attrib['command'] || $attrib['name'] || $attrib['onclick'])) - return ''; - - // try to find out the button type - if ($attrib['type']) - $attrib['type'] = strtolower($attrib['type']); - else - $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link'; - - $command = $attrib['command']; - - // take the button from the stack - if($attrib['name'] && $sa_buttons[$attrib['name']]) - $attrib = $sa_buttons[$attrib['name']]; - - // add button to button stack - else if($attrib['image'] || $attrib['imageact'] || $attrib['imagepas'] || $attrib['class']) - { - if (!$attrib['name']) - $attrib['name'] = $command; - - if (!$attrib['image']) - $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact']; - - $sa_buttons[$attrib['name']] = $attrib; - } - - // get saved button for this command/name - else if ($command && $sa_buttons[$command]) - $attrib = $sa_buttons[$command]; - - //else - // return ''; - - - // set border to 0 because of the link arround the button - if ($attrib['type']=='image' && !isset($attrib['border'])) - $attrib['border'] = 0; - - if (!$attrib['id']) - $attrib['id'] = sprintf('rcmbtn%d', $s_button_count++); - - // get localized text for labels and titles - if ($attrib['title']) - $attrib['title'] = Q(rcube_label($attrib['title'])); - if ($attrib['label']) - $attrib['label'] = Q(rcube_label($attrib['label'])); - - if ($attrib['alt']) - $attrib['alt'] = Q(rcube_label($attrib['alt'])); - - // set title to alt attribute for IE browsers - if ($BROWSER['ie'] && $attrib['title'] && !$attrib['alt']) - { - $attrib['alt'] = $attrib['title']; - unset($attrib['title']); - } - - // add empty alt attribute for XHTML compatibility - if (!isset($attrib['alt'])) - $attrib['alt'] = ''; - - - // register button in the system - if ($attrib['command']) - { - $this->add_script(sprintf( - "%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');", - JS_OBJECT_NAME, - $command, - $attrib['id'], - $attrib['type'], - $attrib['imageact'] ? $skin_path.$attrib['imageact'] : $attrib['classact'], - $attrib['imagesel'] ? $skin_path.$attrib['imagesel'] : $attrib['classsel'], - $attrib['imageover'] ? $skin_path.$attrib['imageover'] : '') - ); - - // make valid href to specific buttons - if (in_array($attrib['command'], $MAIN_TASKS)) - $attrib['href'] = Q(rcmail_url(null, null, $attrib['command'])); - else if (in_array($attrib['command'], $a_static_commands)) - $attrib['href'] = Q(rcmail_url($attrib['command'])); - } - - // overwrite attributes - if (!$attrib['href']) - $attrib['href'] = '#'; - - if ($command) - $attrib['onclick'] = sprintf("return %s.command('%s','%s',this)", JS_OBJECT_NAME, $command, $attrib['prop']); - - if ($command && $attrib['imageover']) - { - $attrib['onmouseover'] = sprintf("return %s.button_over('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']); - $attrib['onmouseout'] = sprintf("return %s.button_out('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']); - } - - if ($command && $attrib['imagesel']) - { - $attrib['onmousedown'] = sprintf("return %s.button_sel('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']); - $attrib['onmouseup'] = sprintf("return %s.button_out('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']); - } - - $out = ''; - - // generate image tag - if ($attrib['type']=='image') - { - $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'align', 'alt')); - $img_tag = sprintf('', $attrib_str); - $btn_content = sprintf($img_tag, $skin_path.$attrib['image']); - if ($attrib['label']) - $btn_content .= ' '.$attrib['label']; - - $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title'); - } - else if ($attrib['type']=='link') - { - $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command']; - $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style'); - } - else if ($attrib['type']=='input') - { - $attrib['type'] = 'button'; - - if ($attrib['label']) - $attrib['value'] = $attrib['label']; - - $attrib_str = create_attrib_string($attrib, array('type', 'value', 'onclick', 'id', 'class', 'style')); - $out = sprintf('', $attrib_str); - } - - // generate html code for button - if ($btn_content) - { - $attrib_str = create_attrib_string($attrib, $link_attrib); - $out = sprintf('%s', $attrib_str, $btn_content); - } - - return $out; - } - -} // end class rcmail_template - - - -// ************** common functions delivering gui objects ************** - - -/** - * Builder for GUI object 'message' - * - * @param array Named tag parameters - * @return string HTML code for the gui object - */ -function rcmail_message_container($attrib) - { - global $OUTPUT; - - if (!$attrib['id']) - $attrib['id'] = 'rcmMessageContainer'; - - // allow the following attributes to be added to the tag - $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id')); - $out = '"; - - $OUTPUT->add_gui_object('message', $attrib['id']); - - return $out; - } - - -/** - * GUI object 'username' - * Showing IMAP username of the current session - * - * @param array Named tag parameters (currently not used) - * @return string HTML code for the gui object - */ -function rcmail_current_username($attrib) - { - global $USER; - static $s_username; - - // alread fetched - if (!empty($s_username)) - return $s_username; - - if ($sql_arr = $USER->get_identity()) - $s_username = $sql_arr['email']; - else if (strstr($_SESSION['username'], '@')) - $s_username = $_SESSION['username']; - else - $s_username = $_SESSION['username'].'@'.$_SESSION['imap_host']; - - return $s_username; - } - - -/** - * GUI object 'loginform' - * Returns code for the webmail login form - * - * @param array Named parameters - * @return string HTML code for the gui object - */ -function rcmail_login_form($attrib) - { - global $CONFIG, $OUTPUT, $SESS_HIDDEN_FIELD; - - $labels = array(); - $labels['user'] = rcube_label('username'); - $labels['pass'] = rcube_label('password'); - $labels['host'] = rcube_label('server'); - - $input_user = new textfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30) + $attrib); - $input_pass = new passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30) + $attrib); - $input_action = new hiddenfield(array('name' => '_action', 'value' => 'login')); - - $fields = array(); - $fields['user'] = $input_user->show(get_input_value('_user', RCUBE_INPUT_POST)); - $fields['pass'] = $input_pass->show(); - $fields['action'] = $input_action->show(); - - if (is_array($CONFIG['default_host'])) - { - $select_host = new select(array('name' => '_host', 'id' => 'rcmloginhost')); - - foreach ($CONFIG['default_host'] as $key => $value) - { - if (!is_array($value)) - $select_host->add($value, (is_numeric($key) ? $value : $key)); - else - { - unset($select_host); - break; - } - } - - $fields['host'] = isset($select_host) ? $select_host->show(get_input_value('_host', RCUBE_INPUT_POST)) : null; - } - else if (!strlen($CONFIG['default_host'])) - { - $input_host = new textfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30)); - $fields['host'] = $input_host->show(get_input_value('_host', RCUBE_INPUT_POST)); - } - - $form_name = strlen($attrib['form']) ? $attrib['form'] : 'form'; - $form_start = !strlen($attrib['form']) ? '
      ' : ''; - $form_end = !strlen($attrib['form']) ? '' : ''; - - if ($fields['host']) - $form_host = <<
      - - - - -EOF; - - $OUTPUT->add_gui_object('loginform', $form_name); - - $out = << - - - - - - - - -$form_host -
      $fields[host]
      $fields[user]
      $fields[pass]
      -$form_end -EOF; - - return $out; - } - - -/** - * GUI object 'charsetselector' - * - * @param array Named parameters for the select tag - * @return string HTML code for the gui object - */ -function rcmail_charset_selector($attrib) - { - global $OUTPUT; - - // pass the following attributes to the form class - $field_attrib = array('name' => '_charset'); - foreach ($attrib as $attr => $value) - if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex'))) - $field_attrib[$attr] = $value; - - $charsets = array( - 'US-ASCII' => 'ASCII (English)', - 'EUC-JP' => 'EUC-JP (Japanese)', - 'EUC-KR' => 'EUC-KR (Korean)', - 'BIG5' => 'BIG5 (Chinese)', - 'GB2312' => 'GB2312 (Chinese)', - 'ISO-2022-JP' => 'ISO-2022-JP (Japanese)', - 'ISO-8859-1' => 'ISO-8859-1 (Latin-1)', - 'ISO-8859-2' => 'ISO-8895-2 (Central European)', - 'ISO-8859-7' => 'ISO-8859-7 (Greek)', - 'ISO-8859-9' => 'ISO-8859-9 (Turkish)', - 'Windows-1251' => 'Windows-1251 (Cyrillic)', - 'Windows-1252' => 'Windows-1252 (Western)', - 'Windows-1255' => 'Windows-1255 (Hebrew)', - 'Windows-1256' => 'Windows-1256 (Arabic)', - 'Windows-1257' => 'Windows-1257 (Baltic)', - 'UTF-8' => 'UTF-8' - ); - - $select = new select($field_attrib); - $select->add(array_values($charsets), array_keys($charsets)); - - $set = $_POST['_charset'] ? $_POST['_charset'] : $OUTPUT->get_charset(); - return $select->show($set); - } - - -/** - * GUI object 'searchform' - * Returns code for search function - * - * @param array Named parameters - * @return string HTML code for the gui object - */ -function rcmail_search_form($attrib) - { - global $OUTPUT; - - // add some labels to client - rcube_add_label('searching'); - - $attrib['name'] = '_q'; - - if (empty($attrib['id'])) - $attrib['id'] = 'rcmqsearchbox'; - - $input_q = new textfield($attrib); - $out = $input_q->show(); - - $OUTPUT->add_gui_object('qsearchbox', $attrib['id']); - - // add form tag around text field - if (empty($attrib['form'])) - $out = sprintf( - '
      %s
      ', - JS_OBJECT_NAME, - $out); - - return $out; - } - - -?> diff --git a/program/include/rcube_browser.php b/program/include/rcube_browser.php new file mode 100644 index 0000000..af393d6 --- /dev/null +++ b/program/include/rcube_browser.php @@ -0,0 +1,75 @@ + | + +-----------------------------------------------------------------------+ + + $Id: rcube_browser.php 328 2006-08-30 17:41:21Z thomasb $ + +*/ + +/** + * rcube_browser + * + * Provide details about the client's browser based on the User-Agent header + * + * @package Core + */ +class rcube_browser +{ + function __construct() + { + $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT']; + + $this->ver = 0; + $this->win = stristr($HTTP_USER_AGENT, 'win'); + $this->mac = stristr($HTTP_USER_AGENT, 'mac'); + $this->linux = stristr($HTTP_USER_AGENT, 'linux'); + $this->unix = stristr($HTTP_USER_AGENT, 'unix'); + + $this->ns4 = stristr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie'); + $this->ns = ($this->ns4 || stristr($HTTP_USER_AGENT, 'netscape')); + $this->ie = stristr($HTTP_USER_AGENT, 'msie'); + $this->mz = stristr($HTTP_USER_AGENT, 'mozilla/5'); + $this->opera = stristr($HTTP_USER_AGENT, 'opera'); + $this->safari = stristr($HTTP_USER_AGENT, 'safari'); + + if ($this->ns) { + $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $this->ver = $test ? (float)$regs[1] : 0; + } + if ($this->mz) { + $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $this->ver = $test ? (float)$regs[1] : 0; + } + if($this->ie) { + $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $this->ver = $test ? (float)$regs[1] : 0; + } + if ($this->opera) { + $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $this->ver = $test ? (float)$regs[1] : 0; + } + + if (eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs)) + $this->lang = $regs[1]; + else + $this->lang = 'en'; + + $this->dom = ($this->mz || $this->safari || ($this->ie && $this->ver>=5) || ($this->opera && $this->ver>=7)); + $this->pngalpha = $this->mz || $this->safari || ($this->ie && $this->ver>=5.5) || + ($this->ie && $this->ver>=5 && $this->mac) || ($this->opera && $this->ver>=7) ? true : false; + } + } + diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php new file mode 100644 index 0000000..8e956de --- /dev/null +++ b/program/include/rcube_config.php @@ -0,0 +1,181 @@ + | + +-----------------------------------------------------------------------+ + + $Id: $ + +*/ + +/** + * Configuration class for RoundCube + * + * @package Core + */ +class rcube_config +{ + private $prop = array(); + + + /** + * Object constructor + */ + public function __construct() + { + $this->load(); + } + + + /** + * Load config from local config file + * + * @todo Remove global $CONFIG + */ + private function load() + { + // start output buffering, we don't need any output yet, + // it'll be cleared after reading of config files, etc. + ob_start(); + + // load main config file + include_once(INSTALL_PATH . 'config/main.inc.php'); + $this->prop = (array)$rcmail_config; + + // load database config + include_once(INSTALL_PATH . 'config/db.inc.php'); + $this->prop += (array)$rcmail_config; + + // load host-specific configuration + $this->load_host_config(); + + // fix paths + $this->prop['skin_path'] = $this->prop['skin_path'] ? unslashify($this->prop['skin_path']) : 'skins/default'; + $this->prop['log_dir'] = $this->prop['log_dir'] ? unslashify($this->prop['log_dir']) : INSTALL_PATH . 'logs'; + + // handle aliases + if (isset($this->prop['locale_string']) && empty($this->prop['language'])) + $this->prop['language'] = $this->prop['locale_string']; + + // set PHP error logging according to config + if ($this->prop['debug_level'] & 1) { + ini_set('log_errors', 1); + ini_set('error_log', $this->prop['log_dir'] . '/errors'); + } + if ($this->prop['debug_level'] & 4) { + ini_set('display_errors', 1); + } + else { + ini_set('display_errors', 0); + } + + // clear output buffer + ob_end_clean(); + + // export config data + $GLOBALS['CONFIG'] = &$this->prop; + } + + + /** + * Load a host-specific config file if configured + * This will merge the host specific configuration with the given one + */ + private function load_host_config() + { + $fname = null; + + if (is_array($this->prop['include_host_config'])) { + $fname = $this->prop['include_host_config'][$_SERVER['HTTP_HOST']]; + } + else if (!empty($this->prop['include_host_config'])) { + $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $_SERVER['HTTP_HOST']) . '.inc.php'; + } + + if ($fname && is_file(INSTALL_PATH . 'config/' . $fname)) { + include(INSTALL_PATH . 'config/' . $fname); + $this->prop = array_merge($this->prop, (array)$rcmail_config); + } + } + + + /** + * Getter for a specific config parameter + * + * @param string Parameter name + * @param mixed Default value if not set + * @return mixed The requested config value + */ + public function get($name, $def = null) + { + return isset($this->prop[$name]) ? $this->prop[$name] : $def; + } + + + /** + * Setter for a config parameter + * + * @param string Parameter name + * @param mixed Parameter value + */ + public function set($name, $value) + { + $this->prop[$name] = $value; + } + + + /** + * Override config options with the given values (eg. user prefs) + * + * @param array Hash array with config props to merge over + */ + public function merge($prefs) + { + $this->prop = array_merge($this->prop, $prefs); + } + + + /** + * Getter for all config options + * + * @return array Hash array containg all config properties + */ + public function all() + { + return $this->prop; + } + + + /** + * Return a 24 byte key for the DES encryption + * + * @return string DES encryption key + */ + public function get_des_key() + { + $key = !empty($this->prop['des_key']) ? $this->prop['des_key'] : 'rcmail?24BitPwDkeyF**ECB'; + $len = strlen($key); + + // make sure the key is exactly 24 chars long + if ($len<24) + $key .= str_repeat('_', 24-$len); + else if ($len>24) + substr($key, 0, 24); + + return $key; + } + + +} + diff --git a/program/include/rcube_contacts.inc b/program/include/rcube_contacts.inc deleted file mode 100644 index 6a48656..0000000 --- a/program/include/rcube_contacts.inc +++ /dev/null @@ -1,458 +0,0 @@ - | - +-----------------------------------------------------------------------+ - - $Id: rcube_contacts.inc 328 2006-08-30 17:41:21Z thomasb $ - -*/ - - -/** - * Model class for the local address book database - * - * @package Addressbook - */ -class rcube_contacts -{ - var $db = null; - var $db_name = ''; - var $user_id = 0; - var $filter = null; - var $result = null; - var $search_fields; - var $search_string; - var $table_cols = array('name', 'email', 'firstname', 'surname'); - - /** public properties */ - var $primary_key = 'contact_id'; - var $readonly = false; - var $list_page = 1; - var $page_size = 10; - var $ready = false; - - - /** - * Object constructor - * - * @param object Instance of the rcube_db class - * @param integer User-ID - */ - function __construct($dbconn, $user) - { - $this->db = $dbconn; - $this->db_name = get_table_name('contacts'); - $this->user_id = $user; - $this->ready = $this->db && !$this->db->is_error(); - } - - /** - * PHP 4 object constructor - * - * @see rcube_contacts::__construct() - */ - function rcube_contacts($dbconn, $user) - { - $this->__construct($dbconn, $user); - } - - - /** - * Set internal list page - * - * @param number Page number to list - * @access public - */ - function set_page($page) - { - $this->list_page = (int)$page; - } - - - /** - * Set internal page size - * - * @param number Number of messages to display on one page - * @access public - */ - function set_pagesize($size) - { - $this->page_size = (int)$size; - } - - - /** - * Save a search string for future listings - * - * @param string SQL params to use in listing method - */ - function set_search_set($filter) - { - $this->filter = $filter; - } - - - /** - * Getter for saved search properties - * - * @return mixed Search properties used by this class - */ - function get_search_set() - { - return $this->filter; - } - - - /** - * Reset all saved results and search parameters - */ - function reset() - { - $this->result = null; - $this->filter = null; - $this->search_fields = null; - $this->search_string = null; - } - - - /** - * Close connection to source - * Called on script shutdown - */ - function close(){} - - - /** - * List the current set of contact records - * - * @param array List of cols to show - * @param int Only return this number of records, use negative values for tail - * @return array Indexed list of contact records, each a hash array - */ - function list_records($cols=null, $subset=0) - { - // count contacts for this user - $this->result = $this->count(); - $sql_result = NULL; - - // get contacts from DB - if ($this->result->count) - { - $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first; - $length = $subset != 0 ? abs($subset) : $this->page_size; - - $sql_result = $this->db->limitquery( - "SELECT * FROM ".$this->db_name." - WHERE del<>1 - AND user_id=?" . - ($this->filter ? " AND (".$this->filter.")" : "") . - " ORDER BY name", - $start_row, - $length, - $this->user_id); - } - - while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) - { - $sql_arr['ID'] = $sql_arr[$this->primary_key]; - // make sure we have a name to display - if (empty($sql_arr['name'])) - $sql_arr['name'] = $sql_arr['email']; - $this->result->add($sql_arr); - } - - return $this->result; - } - - - /** - * Search contacts - * - * @param array List of fields to search in - * @param string Search value - * @param boolean True if results are requested, False if count only - * @return Indexed list of contact records and 'count' value - */ - function search($fields, $value, $strict=false, $select=true) - { - if (!is_array($fields)) - $fields = array($fields); - - $add_where = array(); - foreach ($fields as $col) - { - if ($col == 'ID' || $col == $this->primary_key) - { - $ids = !is_array($value) ? split(',', $value) : $value; - $add_where[] = $this->primary_key." IN (".join(',', $ids).")"; - } - else if ($strict) - $add_where[] = $this->db->quoteIdentifier($col)."=".$this->db->quote($value); - else - $add_where[] = $this->db->quoteIdentifier($col)." LIKE ".$this->db->quote(strlen($value)>2 ? "%$value%" : "$value%"); - } - - if (!empty($add_where)) - { - $this->set_search_set(join(' OR ', $add_where)); - if ($select) - $this->list_records(); - else - $this->result = $this->count(); - } - - return $this->result; - } - - - /** - * Count number of available contacts in database - * - * @return Result array with values for 'count' and 'first' - */ - function count() - { - // count contacts for this user - $sql_result = $this->db->query( - "SELECT COUNT(contact_id) AS rows - FROM ".$this->db_name." - WHERE del<>1 - AND user_id=?". - ($this->filter ? " AND (".$this->filter.")" : ""), - $this->user_id); - - $sql_arr = $this->db->fetch_assoc($sql_result); - return new rcube_result_set($sql_arr['rows'], ($this->list_page-1) * $this->page_size);; - } - - - /** - * Return the last result set - * - * @return Result array or NULL if nothing selected yet - */ - function get_result($as_res=true) - { - return $this->result; - } - - - /** - * Get a specific contact record - * - * @param mixed record identifier(s) - * @return Result object with all record fields or False if not found - */ - function get_record($id, $assoc=false) - { - // return cached result - if ($this->result && ($first = $this->result->first()) && $first[$this->primary_key] == $id) - return $assoc ? $first : $this->result; - - $this->db->query( - "SELECT * FROM ".$this->db_name." - WHERE contact_id=? - AND user_id=? - AND del<>1", - $id, - $this->user_id); - - if ($sql_arr = $this->db->fetch_assoc()) - { - $sql_arr['ID'] = $sql_arr[$this->primary_key]; - $this->result = new rcube_result_set(1); - $this->result->add($sql_arr); - } - - return $assoc && $sql_arr ? $sql_arr : $this->result; - } - - - /** - * Create a new contact record - * - * @param array Assoziative array with save data - * @return The created record ID on success, False on error - */ - function insert($save_data, $check=false) - { - if (is_object($save_data) && is_a($save_data, rcube_result_set)) - return $this->insert_recset($save_data, $check); - - $insert_id = $existing = false; - - if ($check) - $existing = $this->search('email', $save_data['email'], true, false); - - $a_insert_cols = $a_insert_values = array(); - foreach ($this->table_cols as $col) - if (isset($save_data[$col])) - { - $a_insert_cols[] = $this->db->quoteIdentifier($col); - $a_insert_values[] = $this->db->quote($save_data[$col]); - } - - if (!$existing->count && !empty($a_insert_cols)) - { - $this->db->query( - "INSERT INTO ".$this->db_name." - (user_id, changed, del, ".join(', ', $a_insert_cols).") - VALUES (?, ".$this->db->now().", 0, ".join(', ', $a_insert_values).")", - $this->user_id); - - $insert_id = $this->db->insert_id(get_sequence_name('contacts')); - } - - return $insert_id; - } - - - /** - * Insert new contacts for each row in set - */ - function insert_recset($result, $check=false) - { - $ids = array(); - while ($row = $result->next()) - { - if ($insert = $this->insert($row, $check)) - $ids[] = $insert; - } - return $ids; - } - - - /** - * Update a specific contact record - * - * @param mixed Record identifier - * @param array Assoziative array with save data - * @return True on success, False on error - */ - function update($id, $save_cols) - { - $updated = false; - $write_sql = array(); - foreach ($this->table_cols as $col) - if (isset($save_cols[$col])) - $write_sql[] = sprintf("%s=%s", $this->db->quoteIdentifier($col), $this->db->quote($save_cols[$col])); - - if (!empty($write_sql)) - { - $this->db->query( - "UPDATE ".$this->db_name." - SET changed=".$this->db->now().", ".join(', ', $write_sql)." - WHERE contact_id=? - AND user_id=? - AND del<>1", - $id, - $this->user_id); - - $updated = $this->db->affected_rows(); - } - - return $updated; - } - - - /** - * Mark one or more contact records as deleted - * - * @param array Record identifiers - */ - function delete($ids) - { - if (is_array($ids)) - $ids = join(',', $ids); - - $this->db->query( - "UPDATE ".$this->db_name." - SET del=1 - WHERE user_id=? - AND contact_id IN (".$ids.")", - $this->user_id); - - return $this->db->affected_rows(); - } - - - /** - * Remove all records from the database - */ - function delete_all() - { - if (is_array($ids)) - $ids = join(',', $ids); - - $this->db->query("DELETE FROM {$this->db_name} WHERE user_id=?", $this->user_id); - return $this->db->affected_rows(); - } - -} - - -/** - * RoundCube result set class. - * Representing an address directory result set. - */ -class rcube_result_set -{ - var $count = 0; - var $first = 0; - var $current = 0; - var $records = array(); - - function __construct($c=0, $f=0) - { - $this->count = (int)$c; - $this->first = (int)$f; - } - - function rcube_result_set($c=0, $f=0) - { - $this->__construct($c, $f); - } - - function add($rec) - { - $this->records[] = $rec; - } - - function iterate() - { - return $this->records[$this->current++]; - } - - function first() - { - $this->current = 0; - return $this->records[$this->current++]; - } - - // alias - function next() - { - return $this->iterate(); - } - - function seek($i) - { - $this->current = $i; - } - -} - - -?> \ No newline at end of file diff --git a/program/include/rcube_contacts.php b/program/include/rcube_contacts.php new file mode 100644 index 0000000..913f04f --- /dev/null +++ b/program/include/rcube_contacts.php @@ -0,0 +1,400 @@ + | + +-----------------------------------------------------------------------+ + + $Id: rcube_contacts.inc 328 2006-08-30 17:41:21Z thomasb $ + +*/ + + +/** + * Model class for the local address book database + * + * @package Addressbook + */ +class rcube_contacts +{ + var $db = null; + var $db_name = ''; + var $user_id = 0; + var $filter = null; + var $result = null; + var $search_fields; + var $search_string; + var $table_cols = array('name', 'email', 'firstname', 'surname'); + + /** public properties */ + var $primary_key = 'contact_id'; + var $readonly = false; + var $list_page = 1; + var $page_size = 10; + var $ready = false; + + + /** + * Object constructor + * + * @param object Instance of the rcube_db class + * @param integer User-ID + */ + function __construct($dbconn, $user) + { + $this->db = $dbconn; + $this->db_name = get_table_name('contacts'); + $this->user_id = $user; + $this->ready = $this->db && !$this->db->is_error(); + } + + /** + * PHP 4 object constructor + * + * @see rcube_contacts::__construct() + */ + function rcube_contacts($dbconn, $user) + { + $this->__construct($dbconn, $user); + } + + + /** + * Set internal list page + * + * @param number Page number to list + * @access public + */ + function set_page($page) + { + $this->list_page = (int)$page; + } + + + /** + * Set internal page size + * + * @param number Number of messages to display on one page + * @access public + */ + function set_pagesize($size) + { + $this->page_size = (int)$size; + } + + + /** + * Save a search string for future listings + * + * @param string SQL params to use in listing method + */ + function set_search_set($filter) + { + $this->filter = $filter; + } + + + /** + * Getter for saved search properties + * + * @return mixed Search properties used by this class + */ + function get_search_set() + { + return $this->filter; + } + + + /** + * Reset all saved results and search parameters + */ + function reset() + { + $this->result = null; + $this->filter = null; + $this->search_fields = null; + $this->search_string = null; + } + + + /** + * Close connection to source + * Called on script shutdown + */ + function close(){} + + + /** + * List the current set of contact records + * + * @param array List of cols to show + * @param int Only return this number of records, use negative values for tail + * @return array Indexed list of contact records, each a hash array + */ + function list_records($cols=null, $subset=0) + { + // count contacts for this user + $this->result = $this->count(); + $sql_result = NULL; + + // get contacts from DB + if ($this->result->count) + { + $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first; + $length = $subset != 0 ? abs($subset) : $this->page_size; + + $sql_result = $this->db->limitquery( + "SELECT * FROM ".$this->db_name." + WHERE del<>1 + AND user_id=?" . + ($this->filter ? " AND (".$this->filter.")" : "") . + " ORDER BY name", + $start_row, + $length, + $this->user_id); + } + + while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) + { + $sql_arr['ID'] = $sql_arr[$this->primary_key]; + // make sure we have a name to display + if (empty($sql_arr['name'])) + $sql_arr['name'] = $sql_arr['email']; + $this->result->add($sql_arr); + } + + return $this->result; + } + + + /** + * Search contacts + * + * @param array List of fields to search in + * @param string Search value + * @param boolean True if results are requested, False if count only + * @return Indexed list of contact records and 'count' value + */ + function search($fields, $value, $strict=false, $select=true) + { + if (!is_array($fields)) + $fields = array($fields); + + $add_where = array(); + foreach ($fields as $col) + { + if ($col == 'ID' || $col == $this->primary_key) + { + $ids = !is_array($value) ? split(',', $value) : $value; + $add_where[] = $this->primary_key." IN (".join(',', $ids).")"; + } + else if ($strict) + $add_where[] = $this->db->quoteIdentifier($col)."=".$this->db->quote($value); + else + $add_where[] = $this->db->quoteIdentifier($col)." LIKE ".$this->db->quote(strlen($value)>2 ? "%$value%" : "$value%"); + } + + if (!empty($add_where)) + { + $this->set_search_set(join(' OR ', $add_where)); + if ($select) + $this->list_records(); + else + $this->result = $this->count(); + } + + return $this->result; + } + + + /** + * Count number of available contacts in database + * + * @return Result array with values for 'count' and 'first' + */ + function count() + { + // count contacts for this user + $sql_result = $this->db->query( + "SELECT COUNT(contact_id) AS rows + FROM ".$this->db_name." + WHERE del<>1 + AND user_id=?". + ($this->filter ? " AND (".$this->filter.")" : ""), + $this->user_id); + + $sql_arr = $this->db->fetch_assoc($sql_result); + return new rcube_result_set($sql_arr['rows'], ($this->list_page-1) * $this->page_size);; + } + + + /** + * Return the last result set + * + * @return Result array or NULL if nothing selected yet + */ + function get_result($as_res=true) + { + return $this->result; + } + + + /** + * Get a specific contact record + * + * @param mixed record identifier(s) + * @return Result object with all record fields or False if not found + */ + function get_record($id, $assoc=false) + { + // return cached result + if ($this->result && ($first = $this->result->first()) && $first[$this->primary_key] == $id) + return $assoc ? $first : $this->result; + + $this->db->query( + "SELECT * FROM ".$this->db_name." + WHERE contact_id=? + AND user_id=? + AND del<>1", + $id, + $this->user_id); + + if ($sql_arr = $this->db->fetch_assoc()) + { + $sql_arr['ID'] = $sql_arr[$this->primary_key]; + $this->result = new rcube_result_set(1); + $this->result->add($sql_arr); + } + + return $assoc && $sql_arr ? $sql_arr : $this->result; + } + + + /** + * Create a new contact record + * + * @param array Assoziative array with save data + * @return The created record ID on success, False on error + */ + function insert($save_data, $check=false) + { + if (is_object($save_data) && is_a($save_data, rcube_result_set)) + return $this->insert_recset($save_data, $check); + + $insert_id = $existing = false; + + if ($check) + $existing = $this->search('email', $save_data['email'], true, false); + + $a_insert_cols = $a_insert_values = array(); + foreach ($this->table_cols as $col) + if (isset($save_data[$col])) + { + $a_insert_cols[] = $this->db->quoteIdentifier($col); + $a_insert_values[] = $this->db->quote($save_data[$col]); + } + + if (!$existing->count && !empty($a_insert_cols)) + { + $this->db->query( + "INSERT INTO ".$this->db_name." + (user_id, changed, del, ".join(', ', $a_insert_cols).") + VALUES (?, ".$this->db->now().", 0, ".join(', ', $a_insert_values).")", + $this->user_id); + + $insert_id = $this->db->insert_id(get_sequence_name('contacts')); + } + + return $insert_id; + } + + + /** + * Insert new contacts for each row in set + */ + function insert_recset($result, $check=false) + { + $ids = array(); + while ($row = $result->next()) + { + if ($insert = $this->insert($row, $check)) + $ids[] = $insert; + } + return $ids; + } + + + /** + * Update a specific contact record + * + * @param mixed Record identifier + * @param array Assoziative array with save data + * @return True on success, False on error + */ + function update($id, $save_cols) + { + $updated = false; + $write_sql = array(); + foreach ($this->table_cols as $col) + if (isset($save_cols[$col])) + $write_sql[] = sprintf("%s=%s", $this->db->quoteIdentifier($col), $this->db->quote($save_cols[$col])); + + if (!empty($write_sql)) + { + $this->db->query( + "UPDATE ".$this->db_name." + SET changed=".$this->db->now().", ".join(', ', $write_sql)." + WHERE contact_id=? + AND user_id=? + AND del<>1", + $id, + $this->user_id); + + $updated = $this->db->affected_rows(); + } + + return $updated; + } + + + /** + * Mark one or more contact records as deleted + * + * @param array Record identifiers + */ + function delete($ids) + { + if (is_array($ids)) + $ids = join(',', $ids); + + $this->db->query( + "UPDATE ".$this->db_name." + SET del=1 + WHERE user_id=? + AND contact_id IN (".$ids.")", + $this->user_id); + + return $this->db->affected_rows(); + } + + + /** + * Remove all records from the database + */ + function delete_all() + { + $this->db->query("DELETE FROM {$this->db_name} WHERE user_id=?", $this->user_id); + return $this->db->affected_rows(); + } + +} diff --git a/program/include/rcube_db.inc b/program/include/rcube_db.inc deleted file mode 100644 index c84dd84..0000000 --- a/program/include/rcube_db.inc +++ /dev/null @@ -1,608 +0,0 @@ - | - | Thomas Bruederli | - +-----------------------------------------------------------------------+ - - $Id: rcube_db.inc 1255 2008-04-05 12:49:21Z thomasb $ - -*/ - - -/** - * Obtain the PEAR::DB class that is used for abstraction - */ -require_once 'DB.php'; - -/** - * Database independent query interface - * - * This is a wrapper for the PEAR::DB class - * - * @package Database - * @author David Saez Padros - * @author Thomas Bruederli - * @version 1.17 - * @link http://pear.php.net/package/DB - */ -class rcube_db - { - var $db_dsnw; // DSN for write operations - var $db_dsnr; // DSN for read operations - var $db_connected = false; // Already connected ? - var $db_mode = ''; // Connection mode - var $db_handle = 0; // Connection handle - var $db_pconn = false; // Use persistent connections - var $db_error = false; - var $db_error_msg = ''; - - var $a_query_results = array('dummy'); - var $last_res_id = 0; - - - /** - * Object constructor - * - * @param string DSN for read/write operations - * @param string Optional DSN for read only operations - */ - function __construct($db_dsnw, $db_dsnr='', $pconn=false) - { - if ($db_dsnr=='') - $db_dsnr=$db_dsnw; - - $this->db_dsnw = $db_dsnw; - $this->db_dsnr = $db_dsnr; - $this->db_pconn = $pconn; - - $dsn_array = DB::parseDSN($db_dsnw); - $this->db_provider = $dsn_array['phptype']; - } - - - /** - * PHP 4 object constructor - * - * @see rcube_db::__construct - */ - function rcube_db($db_dsnw, $db_dsnr='', $pconn=false) - { - $this->__construct($db_dsnw, $db_dsnr, $pconn); - } - - - /** - * Connect to specific database - * - * @param string DSN for DB connections - * @return object PEAR database handle - * @access private - */ - function dsn_connect($dsn) - { - // Use persistent connections if available - $dbh = DB::connect($dsn, array('persistent' => $this->db_pconn)); - - if (DB::isError($dbh)) - { - $this->db_error = TRUE; - $this->db_error_msg = $dbh->getMessage(); - - raise_error(array('code' => 603, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $this->db_error_msg), TRUE, FALSE); - - return FALSE; - } - - else if ($this->db_provider=='sqlite') - { - $dsn_array = DB::parseDSN($dsn); - if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) - $this->_sqlite_create_database($dbh, $this->sqlite_initials); - } - - return $dbh; - } - - - /** - * Connect to appropiate databse - * depending on the operation - * - * @param string Connection mode (r|w) - * @access public - */ - function db_connect($mode) - { - $this->db_mode = $mode; - - // Already connected - if ($this->db_connected) - { - // no replication, current connection is ok - if ($this->db_dsnw==$this->db_dsnr) - return; - - // connected to master, current connection is ok - if ($this->db_mode=='w') - return; - - // Same mode, current connection is ok - if ($this->db_mode==$mode) - return; - } - - if ($mode=='r') - $dsn = $this->db_dsnr; - else - $dsn = $this->db_dsnw; - - $this->db_handle = $this->dsn_connect($dsn); - $this->db_connected = $this->db_handle ? TRUE : FALSE; - } - - - /** - * Activate/deactivate debug mode - * (not implemented) - */ - function set_debug($dbg = true) - { - - } - - - /** - * Getter for error state - * - * @param boolean True on error - */ - function is_error() - { - return $this->db_error ? $this->db_error_msg : FALSE; - } - - - /** - * Execute a SQL query - * - * @param string SQL query to execute - * @param mixed Values to be inserted in query - * @return number Query handle identifier - * @access public - */ - function query() - { - $params = func_get_args(); - $query = array_shift($params); - - return $this->_query($query, 0, 0, $params); - } - - - /** - * Execute a SQL query with limits - * - * @param string SQL query to execute - * @param number Offset for LIMIT statement - * @param number Number of rows for LIMIT statement - * @param mixed Values to be inserted in query - * @return number Query handle identifier - * @access public - */ - function limitquery() - { - $params = func_get_args(); - $query = array_shift($params); - $offset = array_shift($params); - $numrows = array_shift($params); - - return $this->_query($query, $offset, $numrows, $params); - } - - - /** - * Execute a SQL query with limits - * - * @param string SQL query to execute - * @param number Offset for LIMIT statement - * @param number Number of rows for LIMIT statement - * @param array Values to be inserted in query - * @return number Query handle identifier - * @access private - */ - function _query($query, $offset, $numrows, $params) - { - // Read or write ? - if (strtolower(trim(substr($query,0,6)))=='select') - $mode='r'; - else - $mode='w'; - - $this->db_connect($mode); - - if (!$this->db_connected) - return FALSE; - - if ($this->db_provider == 'sqlite') - $this->_sqlite_prepare(); - - if ($numrows || $offset) - $result = $this->db_handle->limitQuery($query,$offset,$numrows,$params); - else - $result = $this->db_handle->query($query, $params); - - // add result, even if it's an error - return $this->_add_result($result); - } - - - /** - * Get number of rows for a SQL query - * If no query handle is specified, the last query will be taken as reference - * - * @param number Optional query handle identifier - * @return mixed Number of rows or FALSE on failure - * @access public - */ - function num_rows($res_id=NULL) - { - if (!$this->db_handle) - return FALSE; - - if ($result = $this->_get_result($res_id)) - return $result->numRows(); - else - return FALSE; - } - - - /** - * Get number of affected rows fort he last query - * - * @return mixed Number of rows or FALSE on failure - * @access public - */ - function affected_rows() - { - if (!$this->db_handle) - return FALSE; - - return $this->db_handle->affectedRows(); - } - - - /** - * Get last inserted record ID - * For Postgres databases, a sequence name is required - * - * @param string Sequence name for increment - * @return mixed ID or FALSE on failure - * @access public - */ - function insert_id($sequence = '') - { - if (!$this->db_handle || $this->db_mode=='r') - return FALSE; - - switch($this->db_provider) - { - case 'pgsql': - $result = &$this->db_handle->getOne("SELECT CURRVAL('$sequence')"); - if (DB::isError($result)) - raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $result->getMessage()), TRUE, FALSE); - return $result; - - case 'mssql': - $result = &$this->db_handle->getOne("SELECT @@IDENTITY"); - if (DB::isError($result)) - raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $result->getMessage()), TRUE, FALSE); - return $result; - - case 'mysql': // This is unfortuneate - return mysql_insert_id($this->db_handle->connection); - - case 'mysqli': - return mysqli_insert_id($this->db_handle->connection); - - case 'sqlite': - return sqlite_last_insert_rowid($this->db_handle->connection); - - default: - die("portability issue with this database, please have the developer fix"); - } - } - - - /** - * Get an associative array for one row - * If no query handle is specified, the last query will be taken as reference - * - * @param number Optional query handle identifier - * @return mixed Array with col values or FALSE on failure - * @access public - */ - function fetch_assoc($res_id=NULL) - { - $result = $this->_get_result($res_id); - return $this->_fetch_row($result, DB_FETCHMODE_ASSOC); - } - - - /** - * Get an index array for one row - * If no query handle is specified, the last query will be taken as reference - * - * @param number Optional query handle identifier - * @return mixed Array with col values or FALSE on failure - * @access public - */ - function fetch_array($res_id=NULL) - { - $result = $this->_get_result($res_id); - return $this->_fetch_row($result, DB_FETCHMODE_ORDERED); - } - - - /** - * Get co values for a result row - * - * @param object Query result handle - * @param number Fetch mode identifier - * @return mixed Array with col values or FALSE on failure - * @access private - */ - function _fetch_row($result, $mode) - { - if (!$result || DB::isError($result)) - { - raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $this->db_link->getMessage()), TRUE, FALSE); - return FALSE; - } - elseif (!is_object($result)) - return FALSE; - - return $result->fetchRow($mode); - } - - - /** - * Formats input so it can be safely used in a query - * - * @param mixed Value to quote - * @return string Quoted/converted string for use in query - * @access public - */ - function quote($input) - { - // create DB handle if not available - if (!$this->db_handle) - $this->db_connect('r'); - - // escape pear identifier chars - $rep_chars = array('?' => '\?', - '!' => '\!', - '&' => '\&'); - - return $this->db_handle->quoteSmart(strtr($input, $rep_chars)); - } - - - /** - * Quotes a string so it can be safely used as a table or column name - * - * @param string Value to quote - * @return string Quoted string for use in query - * @deprecated Replaced by rcube_db::quote_identifier - * @see rcube_db::quote_identifier - * @access public - */ - function quoteIdentifier($str) - { - return $this->quote_identifier($str); - } - - - /** - * Quotes a string so it can be safely used as a table or column name - * - * @param string Value to quote - * @return string Quoted string for use in query - * @access public - */ - function quote_identifier($str) - { - if (!$this->db_handle) - $this->db_connect('r'); - - return $this->db_handle->quoteIdentifier($str); - } - - - /** - * Escapes a string - * - * @param string The string to be escaped - * @return string The escaped string - * @access public - */ - function escapeSimple($str) - { - if (!$this->db_handle) - $this->db_connect('r'); - - return $this->db_handle->escapeSimple($str); - } - - - /* - * Return SQL function for current time and date - * - * @return string SQL function to use in query - * @access public - */ - function now() - { - switch($this->db_provider) - { - case 'mssql': - return "getdate()"; - - default: - return "now()"; - } - } - - - /** - * Return SQL statement to convert a field value into a unix timestamp - * - * @param string Field name - * @return string SQL statement to use in query - * @access public - */ - function unixtimestamp($field) - { - switch($this->db_provider) - { - case 'pgsql': - return "EXTRACT (EPOCH FROM $field)"; - - case 'mssql': - return "datediff(s, '1970-01-01 00:00:00', $field)"; - - default: - return "UNIX_TIMESTAMP($field)"; - } - } - - - /** - * Return SQL statement to convert from a unix timestamp - * - * @param string Field name - * @return string SQL statement to use in query - * @access public - */ - function fromunixtime($timestamp) - { - switch($this->db_provider) - { - case 'mysqli': - case 'mysql': - case 'sqlite': - return sprintf("FROM_UNIXTIME(%d)", $timestamp); - - default: - return date("'Y-m-d H:i:s'", $timestamp); - } - } - - - /** - * Adds a query result and returns a handle ID - * - * @param object Query handle - * @return mixed Handle ID or FALE on failure - * @access private - */ - function _add_result($res) - { - // sql error occured - if (DB::isError($res)) - { - raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $res->getMessage() . " Query: " . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)), TRUE, FALSE); - return FALSE; - } - else - { - $res_id = sizeof($this->a_query_results); - $this->a_query_results[$res_id] = $res; - $this->last_res_id = $res_id; - return $res_id; - } - } - - - /** - * Resolves a given handle ID and returns the according query handle - * If no ID is specified, the last ressource handle will be returned - * - * @param number Handle ID - * @return mixed Ressource handle or FALE on failure - * @access private - */ - function _get_result($res_id=NULL) - { - if ($res_id==NULL) - $res_id = $this->last_res_id; - - if ($res_id && isset($this->a_query_results[$res_id])) - return $this->a_query_results[$res_id]; - else - return FALSE; - } - - - /** - * Create a sqlite database from a file - * - * @param object SQLite database handle - * @param string File path to use for DB creation - * @access private - */ - function _sqlite_create_database($dbh, $file_name) - { - if (empty($file_name) || !is_string($file_name)) - return; - - $data = ''; - if ($fd = fopen($file_name, 'r')) - { - $data = fread($fd, filesize($file_name)); - fclose($fd); - } - - if (strlen($data)) - sqlite_exec($dbh->connection, $data); - } - - - /** - * Add some proprietary database functions to the current SQLite handle - * in order to make it MySQL compatible - * - * @access private - */ - function _sqlite_prepare() - { - include_once('include/rcube_sqlite.inc'); - - // we emulate via callback some missing MySQL function - sqlite_create_function($this->db_handle->connection, "from_unixtime", "rcube_sqlite_from_unixtime"); - sqlite_create_function($this->db_handle->connection, "unix_timestamp", "rcube_sqlite_unix_timestamp"); - sqlite_create_function($this->db_handle->connection, "now", "rcube_sqlite_now"); - sqlite_create_function($this->db_handle->connection, "md5", "rcube_sqlite_md5"); - } - - - } // end class rcube_db - -?> diff --git a/program/include/rcube_db.php b/program/include/rcube_db.php new file mode 100644 index 0000000..1b0a19e --- /dev/null +++ b/program/include/rcube_db.php @@ -0,0 +1,603 @@ + | + | Thomas Bruederli | + +-----------------------------------------------------------------------+ + + $Id: rcube_db.php 1291 2008-04-12 13:54:45Z thomasb $ + +*/ + + +/** + * Database independent query interface + * + * This is a wrapper for the PEAR::DB class + * + * @package Database + * @author David Saez Padros + * @author Thomas Bruederli + * @version 1.17 + * @link http://pear.php.net/package/DB + */ +class rcube_db + { + var $db_dsnw; // DSN for write operations + var $db_dsnr; // DSN for read operations + var $db_connected = false; // Already connected ? + var $db_mode = ''; // Connection mode + var $db_handle = 0; // Connection handle + var $db_pconn = false; // Use persistent connections + var $db_error = false; + var $db_error_msg = ''; + + var $a_query_results = array('dummy'); + var $last_res_id = 0; + + + /** + * Object constructor + * + * @param string DSN for read/write operations + * @param string Optional DSN for read only operations + */ + function __construct($db_dsnw, $db_dsnr='', $pconn=false) + { + if ($db_dsnr=='') + $db_dsnr=$db_dsnw; + + $this->db_dsnw = $db_dsnw; + $this->db_dsnr = $db_dsnr; + $this->db_pconn = $pconn; + + $dsn_array = DB::parseDSN($db_dsnw); + $this->db_provider = $dsn_array['phptype']; + } + + + /** + * PHP 4 object constructor + * + * @see rcube_db::__construct + */ + function rcube_db($db_dsnw, $db_dsnr='', $pconn=false) + { + $this->__construct($db_dsnw, $db_dsnr, $pconn); + } + + + /** + * Connect to specific database + * + * @param string DSN for DB connections + * @return object PEAR database handle + * @access private + */ + function dsn_connect($dsn) + { + // Use persistent connections if available + $dbh = DB::connect($dsn, array('persistent' => $this->db_pconn)); + + if (DB::isError($dbh)) + { + $this->db_error = TRUE; + $this->db_error_msg = $dbh->getMessage(); + + raise_error(array('code' => 603, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, + 'message' => $this->db_error_msg), TRUE, FALSE); + + return FALSE; + } + + else if ($this->db_provider=='sqlite') + { + $dsn_array = DB::parseDSN($dsn); + if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) + $this->_sqlite_create_database($dbh, $this->sqlite_initials); + } + + return $dbh; + } + + + /** + * Connect to appropiate databse + * depending on the operation + * + * @param string Connection mode (r|w) + * @access public + */ + function db_connect($mode) + { + $this->db_mode = $mode; + + // Already connected + if ($this->db_connected) + { + // no replication, current connection is ok + if ($this->db_dsnw==$this->db_dsnr) + return; + + // connected to master, current connection is ok + if ($this->db_mode=='w') + return; + + // Same mode, current connection is ok + if ($this->db_mode==$mode) + return; + } + + if ($mode=='r') + $dsn = $this->db_dsnr; + else + $dsn = $this->db_dsnw; + + $this->db_handle = $this->dsn_connect($dsn); + $this->db_connected = $this->db_handle ? TRUE : FALSE; + } + + + /** + * Activate/deactivate debug mode + * (not implemented) + */ + function set_debug($dbg = true) + { + + } + + + /** + * Getter for error state + * + * @param boolean True on error + */ + function is_error() + { + return $this->db_error ? $this->db_error_msg : FALSE; + } + + + /** + * Execute a SQL query + * + * @param string SQL query to execute + * @param mixed Values to be inserted in query + * @return number Query handle identifier + * @access public + */ + function query() + { + $params = func_get_args(); + $query = array_shift($params); + + return $this->_query($query, 0, 0, $params); + } + + + /** + * Execute a SQL query with limits + * + * @param string SQL query to execute + * @param number Offset for LIMIT statement + * @param number Number of rows for LIMIT statement + * @param mixed Values to be inserted in query + * @return number Query handle identifier + * @access public + */ + function limitquery() + { + $params = func_get_args(); + $query = array_shift($params); + $offset = array_shift($params); + $numrows = array_shift($params); + + return $this->_query($query, $offset, $numrows, $params); + } + + + /** + * Execute a SQL query with limits + * + * @param string SQL query to execute + * @param number Offset for LIMIT statement + * @param number Number of rows for LIMIT statement + * @param array Values to be inserted in query + * @return number Query handle identifier + * @access private + */ + function _query($query, $offset, $numrows, $params) + { + // Read or write ? + if (strtolower(trim(substr($query,0,6)))=='select') + $mode='r'; + else + $mode='w'; + + $this->db_connect($mode); + + if (!$this->db_connected) + return FALSE; + + if ($this->db_provider == 'sqlite') + $this->_sqlite_prepare(); + + if ($numrows || $offset) + $result = $this->db_handle->limitQuery($query,$offset,$numrows,$params); + else + $result = $this->db_handle->query($query, $params); + + // add result, even if it's an error + return $this->_add_result($result); + } + + + /** + * Get number of rows for a SQL query + * If no query handle is specified, the last query will be taken as reference + * + * @param number Optional query handle identifier + * @return mixed Number of rows or FALSE on failure + * @access public + */ + function num_rows($res_id=NULL) + { + if (!$this->db_handle) + return FALSE; + + if ($result = $this->_get_result($res_id)) + return $result->numRows(); + else + return FALSE; + } + + + /** + * Get number of affected rows fort he last query + * + * @return mixed Number of rows or FALSE on failure + * @access public + */ + function affected_rows() + { + if (!$this->db_handle) + return FALSE; + + return $this->db_handle->affectedRows(); + } + + + /** + * Get last inserted record ID + * For Postgres databases, a sequence name is required + * + * @param string Sequence name for increment + * @return mixed ID or FALSE on failure + * @access public + */ + function insert_id($sequence = '') + { + if (!$this->db_handle || $this->db_mode=='r') + return FALSE; + + switch($this->db_provider) + { + case 'pgsql': + $result = &$this->db_handle->getOne("SELECT CURRVAL('$sequence')"); + if (DB::isError($result)) + raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, + 'message' => $result->getMessage()), TRUE, FALSE); + return $result; + + case 'mssql': + $result = &$this->db_handle->getOne("SELECT @@IDENTITY"); + if (DB::isError($result)) + raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, + 'message' => $result->getMessage()), TRUE, FALSE); + return $result; + + case 'mysql': // This is unfortuneate + return mysql_insert_id($this->db_handle->connection); + + case 'mysqli': + return mysqli_insert_id($this->db_handle->connection); + + case 'sqlite': + return sqlite_last_insert_rowid($this->db_handle->connection); + + default: + die("portability issue with this database, please have the developer fix"); + } + } + + + /** + * Get an associative array for one row + * If no query handle is specified, the last query will be taken as reference + * + * @param number Optional query handle identifier + * @return mixed Array with col values or FALSE on failure + * @access public + */ + function fetch_assoc($res_id=NULL) + { + $result = $this->_get_result($res_id); + return $this->_fetch_row($result, DB_FETCHMODE_ASSOC); + } + + + /** + * Get an index array for one row + * If no query handle is specified, the last query will be taken as reference + * + * @param number Optional query handle identifier + * @return mixed Array with col values or FALSE on failure + * @access public + */ + function fetch_array($res_id=NULL) + { + $result = $this->_get_result($res_id); + return $this->_fetch_row($result, DB_FETCHMODE_ORDERED); + } + + + /** + * Get co values for a result row + * + * @param object Query result handle + * @param number Fetch mode identifier + * @return mixed Array with col values or FALSE on failure + * @access private + */ + function _fetch_row($result, $mode) + { + if (!$result || DB::isError($result)) + { + raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, + 'message' => $this->db_link->getMessage()), TRUE, FALSE); + return FALSE; + } + elseif (!is_object($result)) + return FALSE; + + return $result->fetchRow($mode); + } + + + /** + * Formats input so it can be safely used in a query + * + * @param mixed Value to quote + * @return string Quoted/converted string for use in query + * @access public + */ + function quote($input) + { + // create DB handle if not available + if (!$this->db_handle) + $this->db_connect('r'); + + // escape pear identifier chars + $rep_chars = array('?' => '\?', + '!' => '\!', + '&' => '\&'); + + return $this->db_handle->quoteSmart(strtr($input, $rep_chars)); + } + + + /** + * Quotes a string so it can be safely used as a table or column name + * + * @param string Value to quote + * @return string Quoted string for use in query + * @deprecated Replaced by rcube_db::quote_identifier + * @see rcube_db::quote_identifier + * @access public + */ + function quoteIdentifier($str) + { + return $this->quote_identifier($str); + } + + + /** + * Quotes a string so it can be safely used as a table or column name + * + * @param string Value to quote + * @return string Quoted string for use in query + * @access public + */ + function quote_identifier($str) + { + if (!$this->db_handle) + $this->db_connect('r'); + + return $this->db_handle->quoteIdentifier($str); + } + + + /** + * Escapes a string + * + * @param string The string to be escaped + * @return string The escaped string + * @access public + */ + function escapeSimple($str) + { + if (!$this->db_handle) + $this->db_connect('r'); + + return $this->db_handle->escapeSimple($str); + } + + + /* + * Return SQL function for current time and date + * + * @return string SQL function to use in query + * @access public + */ + function now() + { + switch($this->db_provider) + { + case 'mssql': + return "getdate()"; + + default: + return "now()"; + } + } + + + /** + * Return SQL statement to convert a field value into a unix timestamp + * + * @param string Field name + * @return string SQL statement to use in query + * @access public + */ + function unixtimestamp($field) + { + switch($this->db_provider) + { + case 'pgsql': + return "EXTRACT (EPOCH FROM $field)"; + + case 'mssql': + return "datediff(s, '1970-01-01 00:00:00', $field)"; + + default: + return "UNIX_TIMESTAMP($field)"; + } + } + + + /** + * Return SQL statement to convert from a unix timestamp + * + * @param string Field name + * @return string SQL statement to use in query + * @access public + */ + function fromunixtime($timestamp) + { + switch($this->db_provider) + { + case 'mysqli': + case 'mysql': + case 'sqlite': + return sprintf("FROM_UNIXTIME(%d)", $timestamp); + + default: + return date("'Y-m-d H:i:s'", $timestamp); + } + } + + + /** + * Adds a query result and returns a handle ID + * + * @param object Query handle + * @return mixed Handle ID or FALE on failure + * @access private + */ + function _add_result($res) + { + // sql error occured + if (DB::isError($res)) + { + raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, + 'message' => $res->getMessage() . " Query: " . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)), TRUE, FALSE); + return FALSE; + } + else + { + $res_id = sizeof($this->a_query_results); + $this->a_query_results[$res_id] = $res; + $this->last_res_id = $res_id; + return $res_id; + } + } + + + /** + * Resolves a given handle ID and returns the according query handle + * If no ID is specified, the last ressource handle will be returned + * + * @param number Handle ID + * @return mixed Ressource handle or FALE on failure + * @access private + */ + function _get_result($res_id=NULL) + { + if ($res_id==NULL) + $res_id = $this->last_res_id; + + if ($res_id && isset($this->a_query_results[$res_id])) + return $this->a_query_results[$res_id]; + else + return FALSE; + } + + + /** + * Create a sqlite database from a file + * + * @param object SQLite database handle + * @param string File path to use for DB creation + * @access private + */ + function _sqlite_create_database($dbh, $file_name) + { + if (empty($file_name) || !is_string($file_name)) + return; + + $data = ''; + if ($fd = fopen($file_name, 'r')) + { + $data = fread($fd, filesize($file_name)); + fclose($fd); + } + + if (strlen($data)) + sqlite_exec($dbh->connection, $data); + } + + + /** + * Add some proprietary database functions to the current SQLite handle + * in order to make it MySQL compatible + * + * @access private + */ + function _sqlite_prepare() + { + include_once('include/rcube_sqlite.inc'); + + // we emulate via callback some missing MySQL function + sqlite_create_function($this->db_handle->connection, "from_unixtime", "rcube_sqlite_from_unixtime"); + sqlite_create_function($this->db_handle->connection, "unix_timestamp", "rcube_sqlite_unix_timestamp"); + sqlite_create_function($this->db_handle->connection, "now", "rcube_sqlite_now"); + sqlite_create_function($this->db_handle->connection, "md5", "rcube_sqlite_md5"); + } + + + } // end class rcube_db + + diff --git a/program/include/rcube_html.inc b/program/include/rcube_html.inc deleted file mode 100644 index d23760a..0000000 --- a/program/include/rcube_html.inc +++ /dev/null @@ -1,667 +0,0 @@ - | - +-----------------------------------------------------------------------+ - - $Id: $ - -*/ - - -/** - * HTML page builder class - * - * @package HTML - */ -class rcube_html_page -{ - var $scripts_path = ''; - var $script_files = array(); - var $scripts = array(); - var $charset = 'UTF-8'; - - var $script_tag_file = "\n"; - var $script_tag = "\n"; - var $default_template = "\n\n\n"; - - var $title = 'RoundCube Mail'; - var $header = ''; - var $footer = ''; - var $body = ''; - var $body_attrib = array(); - var $meta_tags = array(); - - - /** - * Link an external script file - * - * @param string File URL - * @param string Target position [head|foot] - */ - 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; - } - - /** - * Add inline javascript code - * - * @param string JS code snippet - * @param string Target position [head|head_top|foot] - */ - function add_script($script, $position='head') - { - if (!isset($this->scripts[$position])) - $this->scripts[$position] = "\n".rtrim($script); - else - $this->scripts[$position] .= "\n".rtrim($script); - } - - /** - * Add HTML code to the page header - */ - function add_header($str) - { - $this->header .= "\n".$str; - } - - /** - * Add HTML code to the page footer - * To be added right befor - */ - function add_footer($str) - { - $this->footer .= "\n".$str; - } - - /** - * Setter for page title - */ - function set_title($t) - { - $this->title = $t; - } - - - /** - * Setter for output charset. - * To be specified in a meta tag and sent as http-header - */ - function set_charset($charset) - { - global $MBSTRING; - - $this->charset = $charset; - - if ($MBSTRING && function_exists("mb_internal_encoding")) - { - if(!@mb_internal_encoding($charset)) - $MBSTRING = FALSE; - } - } - - /** - * Getter for output charset - */ - function get_charset() - { - return $this->charset; - } - - - /** - * Reset all saved properties - */ - function reset() - { - $this->script_files = array(); - $this->scripts = array(); - $this->title = ''; - $this->header = ''; - $this->footer = ''; - } - - - /** - * Process template and write to stdOut - * - * @param string HTML template - * @param string Base for absolute paths - */ - function write($templ='', $base_path='') - { - $output = empty($templ) ? $this->default_template : trim($templ); - - // replace specialchars in content - $__page_title = Q($this->title, 'show', FALSE); - $__page_header = $__page_body = $__page_footer = ''; - - - // include meta tag with charset - if (!empty($this->charset)) - { - header('Content-Type: text/html; charset='.$this->charset, true); - $__page_header = ''."\n"; - } - - - // 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); - - $head_script = $this->scripts['head_top'] . $this->scripts['head']; - if (!empty($head_script)) - $__page_header .= sprintf($this->script_tag, $head_script); - - if (!empty($this->header)) - $__page_header .= $this->header; - - 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 (!empty($this->scripts['foot'])) - $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']); - - if (!empty($this->footer)) - $__page_footer .= $this->footer; - - // find page header - if ($hpos = strpos(strtolower($output), '')) - $__page_header .= "\n"; - else - { - if (!is_numeric($hpos)) - $hpos = strpos(strtolower($output), '')+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 - $output_lc = strtolower($output); - if(($fpos = strrstr($output_lc, '')) || - ($fpos = strrstr($output_lc, ''))) - $output = substr($output, 0, $fpos) . "$__page_footer\n" . substr($output, $fpos); - else - $output .= "\n$__page_footer"; - - - // reset those global vars - $__page_header = $__page_footer = ''; - - - // correct absolute paths in images and other tags - $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output); - $output = str_replace('$__skin_path', $base_path, $output); - - print rcube_charset_convert($output, 'UTF-8', $this->charset); - } - -} // end class rcube_html_page - - - -/** - * Base class to build a HTML for element - * - * @package HTML - */ -class rcube_form_element - { - var $uppertags = FALSE; - var $upperattribs = FALSE; - var $upperprops = FALSE; - var $newline = FALSE; - - var $attrib = array(); - - - /** - * Create string with saved attributes - * - * @return string HTML formatted tag attributes - */ - function create_attrib_string() - { - 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; - - // attributes with no value - if (in_array($key, array('checked', 'multiple', 'disabled', 'selected', 'nowrap'))) - { - if ($value) - $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $key); - } - // don't convert size of value attribute - else if ($key=='value') - $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), Q($value, 'strict', false)); - - // regular tag attributes - else - $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case(Q($value), 'value')); - } - - return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : ''; - } - - - /** - * Convert tags and attributes to upper-/lowercase - * - * @param string Input string - * @param string Value type (can either be "tag" or "attrib") - * @return string Converted output string - * @access private - */ - 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); - } - } - - -/** - * Builder for an field - * - * @package HTML - */ -class input_field extends rcube_form_element -{ - var $type = 'text'; - - /** - * Constructor - * @param array Named tag attributes - */ - function input_field($attrib=array()) - { - if (is_array($attrib)) - $this->attrib = $attrib; - - if ($attrib['type']) - $this->type = $attrib['type']; - - if ($attrib['newline']) - $this->newline = TRUE; - } - - /** - * Compose input tag - * - * @param string Field value - * @param array Additional tag attributes - * @return string Final HTML code - */ - 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" : "")); - } -} - - -/** - * Builder for a field - * - * @package HTML - */ -class textfield extends input_field -{ - var $type = 'text'; -} - -/** - * Builder for a field - * - * @package HTML - */ -class passwordfield extends input_field -{ - var $type = 'password'; -} - -/** - * Builder for fields - * - * @package HTML - */ -class radiobutton extends input_field -{ - var $type = 'radio'; -} - -/** - * Builder for fields - * - * @package HTML - */ -class checkbox extends input_field -{ - var $type = 'checkbox'; - - - /** - * Compose input tag - * - * @param string Field value - * @param array Additional tag attributes - * @return string Final HTML code - */ - 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" : "")); - } -} - - -/** - * Builder for a ' + ); + } + $output = $this->parse_with_globals($output); + $this->write(trim($output), $skin_path); + if ($exit) { + exit; + } + } + + + /** + * Return executable javascript code for all registered commands + * + * @return string $out + */ + private function get_js_commands() + { + $out = ''; + if (!$this->framed && !empty($this->js_env)) { + $out .= JS_OBJECT_NAME . '.set_env('.json_serialize($this->js_env).");\n"; + } + foreach ($this->js_commands as $i => $args) { + $method = array_shift($args); + foreach ($args as $i => $arg) { + $args[$i] = json_serialize($arg); + } + $parent = $this->framed || preg_match('/^parent\./', $method); + $out .= sprintf( + "%s.%s(%s);\n", + ($parent ? 'parent.' : '') . JS_OBJECT_NAME, + preg_replace('/^parent\./', '', $method), + implode(',', $args) + ); + } + // add command to set page title + if ($this->ajax_call && !empty($this->pagetitle)) { + $out .= sprintf( + "this.set_pagetitle('%s');\n", + JQ((!empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '') . $this->pagetitle) + ); + } + return $out; + } + + /** + * Make URLs starting with a slash point to skin directory + * + * @param string Input string + * @return string + */ + public function abs_url($str) + { + return preg_replace('/^\//', $this->config['skin_path'].'/', $str); + } + + + /***** Template parsing methods *****/ + + /** + * Replace all strings ($varname) + * with the content of the according global variable. + */ + private function parse_with_globals($input) + { + $GLOBALS['__comm_path'] = Q($this->app->comm_path); + return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input); + } + + /** + * Public wrapper to dipp into template parsing. + * + * @param string $input + * @return string + * @uses rcube_template::parse_xml() + * @since 0.1-rc1 + */ + public function just_parse($input) + { + return $this->parse_xml($input); + } + + /** + * Parse for conditional tags + * + * @param string $input + * @return string + */ + private function parse_conditions($input) + { + $matches = preg_split('/]+)>/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE); + if ($matches && count($matches) == 4) { + if (preg_match('/^(else|endif)$/i', $matches[1])) { + return $matches[0] . $this->parse_conditions($matches[3]); + } + $attrib = parse_attrib_string($matches[2]); + if (isset($attrib['condition'])) { + $condmet = $this->check_condition($attrib['condition']); + $submatches = preg_split('/]+)>/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE); + if ($condmet) { + $result = $submatches[0]; + $result.= ($submatches[1] != 'endif' ? preg_replace('/.*]+>/Uis', '', $submatches[3], 1) : $submatches[3]); + } + else { + $result = "" . $submatches[3]; + } + return $matches[0] . $this->parse_conditions($result); + } + raise_error(array( + 'code' => 500, + 'type' => 'php', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => "Unable to parse conditional tag " . $matches[2] + ), true, false); + } + return $input; + } + + + /** + * Determines if a given condition is met + * + * @todo Get rid off eval() once I understand what this does. + * @todo Extend this to allow real conditions, not just "set" + * @param string Condition statement + * @return boolean True if condition is met, False is not + */ + private function check_condition($condition) + { + $condition = preg_replace( + array( + '/session:([a-z0-9_]+)/i', + '/config:([a-z0-9_]+)/i', + '/env:([a-z0-9_]+)/i', + '/request:([a-z0-9_]+)/ie' + ), + array( + "\$_SESSION['\\1']", + "\$this->config['\\1']", + "\$this->env['\\1']", + "get_input_value('\\1', RCUVE_INPUT_GPC)" + ), + $condition); + + return eval("return (".$condition.");"); + } + + + /** + * Search for special tags in input and replace them + * with the appropriate content + * + * @param string Input string to parse + * @return string Altered input string + * @todo Maybe a cache. + */ + private function parse_xml($input) + { + return preg_replace('/]+)>/Uie', "\$this->xml_command('\\1', '\\2')", $input); + } + + + /** + * Convert a xml command tag into real content + * + * @param string Tag command: object,button,label, etc. + * @param string Attribute string + * @return string Tag/Object content + */ + private function xml_command($command, $str_attrib, $add_attrib = array()) + { + $command = strtolower($command); + $attrib = parse_attrib_string($str_attrib) + $add_attrib; + + // empty output if required condition is not met + if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) { + return ''; + } + + // execute command + switch ($command) { + // return a button + case 'button': + if ($attrib['name'] || $attrib['command']) { + return $this->button($attrib); + } + break; + + // show a label + case 'label': + if ($attrib['name'] || $attrib['command']) { + return Q(rcube_label($attrib + array('vars' => array('product' => $this->config['product_name'])))); + } + break; + + // include a file + case 'include': + $path = realpath($this->config['skin_path'].$attrib['file']); + if ($fsize = filesize($path)) { + if ($this->config['skin_include_php']) { + $incl = $this->include_php($path); + } + else if ($fp = fopen($path, 'r')) { + $incl = fread($fp, $fsize); + fclose($fp); + } + return $this->parse_xml($incl); + } + break; + + case 'plugin.include': + //rcube::tfk_debug(var_export($this->config['skin_path'], true)); + $path = realpath($this->config['skin_path'].$attrib['file']); + if (!$path) { + //rcube::tfk_debug("Does not exist:"); + //rcube::tfk_debug($this->config['skin_path']); + //rcube::tfk_debug($attrib['file']); + //rcube::tfk_debug($path); + } + $incl = file_get_contents($path); + if ($incl) { + return $this->parse_xml($incl); + } + break; + + // return code for a specific application object + case 'object': + $object = strtolower($attrib['name']); + + // we are calling a class/method + if (($handler = $this->object_handlers[$object]) && is_array($handler)) { + if ((is_object($handler[0]) && method_exists($handler[0], $handler[1])) || + (is_string($handler[0]) && class_exists($handler[0]))) + return call_user_func($handler, $attrib); + } + else if (function_exists($handler)) { + // execute object handler function + return call_user_func($handler, $attrib); + } + + if ($object=='productname') { + $name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail'; + return Q($name); + } + if ($object=='version') { + $ver = (string)RCMAIL_VERSION; + if (is_file(INSTALL_PATH . '.svn/entries')) { + if (preg_match('/Revision:\s(\d+)/', @shell_exec('svn info'), $regs)) + $ver .= ' [SVN r'.$regs[1].']'; + } + return $ver; + } + if ($object=='pagetitle') { + $task = $this->task; + $title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : ''; + + if (!empty($this->pagetitle)) { + $title .= $this->pagetitle; + } + else if ($task == 'login') { + $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name']))); + } + else { + $title .= ucfirst($task); + } + + return Q($title); + } + break; + + // return variable + case 'var': + $var = explode(':', $attrib['name']); + $name = $var[1]; + $value = ''; + + switch ($var[0]) { + case 'env': + $value = $this->env[$name]; + break; + case 'config': + $value = $this->config[$name]; + if (is_array($value) && $value[$_SESSION['imap_host']]) { + $value = $value[$_SESSION['imap_host']]; + } + break; + case 'request': + $value = get_input_value($name, RCUBE_INPUT_GPC); + break; + case 'session': + $value = $_SESSION[$name]; + break; + } + + if (is_array($value)) { + $value = implode(', ', $value); + } + + return Q($value); + break; + } + return ''; + } + + /** + * Include a specific file and return it's contents + * + * @param string File path + * @return string Contents of the processed file + */ + private function include_php($file) + { + ob_start(); + include $file; + $out = ob_get_contents(); + ob_end_clean(); + + return $out; + } + + /** + * Create and register a button + * + * @param array Named button attributes + * @return string HTML button + * @todo Remove all inline JS calls and use jQuery instead. + * @todo Remove all sprintf()'s - they are pretty, but also slow. + */ + private function button($attrib) + { + static $sa_buttons = array(); + static $s_button_count = 100; + + // these commands can be called directly via url + $a_static_commands = array('compose', 'list'); + + if (!($attrib['command'] || $attrib['name'])) { + return ''; + } + + $browser = new rcube_browser(); + + // try to find out the button type + if ($attrib['type']) { + $attrib['type'] = strtolower($attrib['type']); + } + else { + $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link'; + } + $command = $attrib['command']; + + // take the button from the stack + if ($attrib['name'] && $sa_buttons[$attrib['name']]) { + $attrib = $sa_buttons[$attrib['name']]; + } + else if($attrib['image'] || $attrib['imageact'] || $attrib['imagepas'] || $attrib['class']) { + // add button to button stack + if (!$attrib['name']) { + $attrib['name'] = $command; + } + if (!$attrib['image']) { + $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact']; + } + $sa_buttons[$attrib['name']] = $attrib; + } + else if ($command && $sa_buttons[$command]) { + // get saved button for this command/name + $attrib = $sa_buttons[$command]; + } + + // set border to 0 because of the link arround the button + if ($attrib['type']=='image' && !isset($attrib['border'])) { + $attrib['border'] = 0; + } + if (!$attrib['id']) { + $attrib['id'] = sprintf('rcmbtn%d', $s_button_count++); + } + // get localized text for labels and titles + if ($attrib['title']) { + $attrib['title'] = Q(rcube_label($attrib['title'])); + } + if ($attrib['label']) { + $attrib['label'] = Q(rcube_label($attrib['label'])); + } + if ($attrib['alt']) { + $attrib['alt'] = Q(rcube_label($attrib['alt'])); + } + // set title to alt attribute for IE browsers + if ($browser->ie && $attrib['title'] && !$attrib['alt']) { + $attrib['alt'] = $attrib['title']; + unset($attrib['title']); + } + + // add empty alt attribute for XHTML compatibility + if (!isset($attrib['alt'])) { + $attrib['alt'] = ''; + } + + // register button in the system + if ($attrib['command']) { + $this->add_script(sprintf( + "%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');", + JS_OBJECT_NAME, + $command, + $attrib['id'], + $attrib['type'], + $attrib['imageact'] ? $this->abs_url($attrib['imageact']) : $attrib['classact'], + $attrib['imagesel'] ? $this->abs_url($attrib['imagesel']) : $attrib['classsel'], + $attrib['imageover'] ? $this->abs_url($attrib['imageover']) : '' + )); + + // make valid href to specific buttons + if (in_array($attrib['command'], rcmail::$main_tasks)) { + $attrib['href'] = Q(rcmail_url(null, null, $attrib['command'])); + } + else if (in_array($attrib['command'], $a_static_commands)) { + $attrib['href'] = Q(rcmail_url($attrib['command'])); + } + } + + // overwrite attributes + if (!$attrib['href']) { + $attrib['href'] = '#'; + } + if ($command) { + $attrib['onclick'] = sprintf( + "return %s.command('%s','%s',this)", + JS_OBJECT_NAME, + $command, + $attrib['prop'] + ); + } + if ($command && $attrib['imageover']) { + $attrib['onmouseover'] = sprintf( + "return %s.button_over('%s','%s')", + JS_OBJECT_NAME, + $command, + $attrib['id'] + ); + $attrib['onmouseout'] = sprintf( + "return %s.button_out('%s','%s')", + JS_OBJECT_NAME, + $command, + $attrib['id'] + ); + } + + if ($command && $attrib['imagesel']) { + $attrib['onmousedown'] = sprintf( + "return %s.button_sel('%s','%s')", + JS_OBJECT_NAME, + $command, + $attrib['id'] + ); + $attrib['onmouseup'] = sprintf( + "return %s.button_out('%s','%s')", + JS_OBJECT_NAME, + $command, + $attrib['id'] + ); + } + + $out = ''; + + // generate image tag + if ($attrib['type']=='image') { + $attrib_str = html::attrib_string( + $attrib, + array( + 'style', 'class', 'id', 'width', + 'height', 'border', 'hspace', + 'vspace', 'align', 'alt', + ) + ); + $btn_content = sprintf('', $this->abs_url($attrib['image']), $attrib_str); + if ($attrib['label']) { + $btn_content .= ' '.$attrib['label']; + } + $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title'); + } + else if ($attrib['type']=='link') { + $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command']; + $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style'); + } + else if ($attrib['type']=='input') { + $attrib['type'] = 'button'; + + if ($attrib['label']) { + $attrib['value'] = $attrib['label']; + } + + $attrib_str = html::attrib_string( + $attrib, + array( + 'type', 'value', 'onclick', + 'id', 'class', 'style' + ) + ); + $out = sprintf('', $attrib_str); + } + + // generate html code for button + if ($btn_content) { + $attrib_str = html::attrib_string($attrib, $link_attrib); + $out = sprintf('%s', $attrib_str, $btn_content); + } + + return $out; + } + + + /* ************* common functions delivering gui objects ************** */ + + + /** + * Create a form tag with the necessary hidden fields + * + * @param array Named tag parameters + * @return string HTML code for the form + */ + public function form_tag($attrib, $content = null) + { + if ($this->framed) { + $hiddenfield = new html_hiddenfield(array('name' => '_framed', 'value' => '1')); + $hidden = $hiddenfield->show(); + } + + if (!$content) + $attrib['noclose'] = true; + + return html::tag('form', + $attrib + array('action' => "./", 'method' => "get"), + $hidden . $content); + } + + + /** + * GUI object 'username' + * Showing IMAP username of the current session + * + * @param array Named tag parameters (currently not used) + * @return string HTML code for the gui object + */ + public function current_username($attrib) + { + static $username; + + // alread fetched + if (!empty($username)) { + return $username; + } + + // get e-mail address form default identity + if ($sql_arr = $this->app->user->get_identity()) { + $username = $sql_arr['email']; + } + else { + $username = $this->app->user->get_username(); + } + + return $username; + } + + + /** + * GUI object 'loginform' + * Returns code for the webmail login form + * + * @param array Named parameters + * @return string HTML code for the gui object + */ + private function login_form($attrib) + { + $default_host = $this->config['default_host']; + + $_SESSION['temp'] = true; + + $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30, 'autocomplete' => 'off')); + $input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30)); + $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login')); + $input_host = null; + + if (is_array($default_host)) { + $input_host = new html_select(array('name' => '_host', 'id' => 'rcmloginhost')); + + foreach ($default_host as $key => $value) { + if (!is_array($value)) { + $input_host->add($value, (is_numeric($key) ? $value : $key)); + } + else { + $input_host = null; + break; + } + } + } + else if (!strlen($default_host)) { + $input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30)); + } + + $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form'; + $this->add_gui_object('loginform', $form_name); + + // create HTML table with two cols + $table = new html_table(array('cols' => 2)); + + $table->add('title', html::label('rcmloginuser', Q(rcube_label('username')))); + $table->add(null, $input_user->show(get_input_value('_user', RCUVE_INPUT_POST))); + + $table->add('title', html::label('rcmloginpwd', Q(rcube_label('password')))); + $table->add(null, $input_pass->show()); + + // add host selection row + if (is_object($input_host)) { + $table->add('title', html::label('rcmloginhost', Q(rcube_label('server')))); + $table->add(null, $input_host->show(get_input_value('_host', RCUVE_INPUT_POST))); + } + + $out = $input_action->show(); + $out .= $table->show(); + + // surround html output with a form tag + if (empty($attrib['form'])) { + $out = $this->form_tag(array('name' => $form_name, 'method' => "post"), $out); + } + + return $out; + } + + + /** + * GUI object 'searchform' + * Returns code for search function + * + * @param array Named parameters + * @return string HTML code for the gui object + */ + private function search_form($attrib) + { + // add some labels to client + $this->add_label('searching'); + + $attrib['name'] = '_q'; + + if (empty($attrib['id'])) { + $attrib['id'] = 'rcmqsearchbox'; + } + $input_q = new html_inputfield($attrib); + $out = $input_q->show(); + + $this->add_gui_object('qsearchbox', $attrib['id']); + + // add form tag around text field + if (empty($attrib['form'])) { + $out = $this->form_tag(array( + 'name' => "rcmqsearchform", + 'onsubmit' => JS_OBJECT_NAME . ".command('search');return false;", + 'style' => "display:inline"), + $out); + } + + return $out; + } + + + /** + * Builder for GUI object 'message' + * + * @param array Named tag parameters + * @return string HTML code for the gui object + */ + private function message_container($attrib) + { + if (isset($attrib['id']) === false) { + $attrib['id'] = 'rcmMessageContainer'; + } + + $this->add_gui_object('message', $attrib['id']); + return html::div($attrib, ""); + } + + + /** + * GUI object 'charsetselector' + * + * @param array Named parameters for the select tag + * @return string HTML code for the gui object + */ + static function charset_selector($attrib) + { + // pass the following attributes to the form class + $field_attrib = array('name' => '_charset'); + foreach ($attrib as $attr => $value) { + if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex'))) { + $field_attrib[$attr] = $value; + } + } + $charsets = array( + 'US-ASCII' => 'ASCII (English)', + 'EUC-JP' => 'EUC-JP (Japanese)', + 'EUC-KR' => 'EUC-KR (Korean)', + 'BIG5' => 'BIG5 (Chinese)', + 'GB2312' => 'GB2312 (Chinese)', + 'ISO-2022-JP' => 'ISO-2022-JP (Japanese)', + 'ISO-8859-1' => 'ISO-8859-1 (Latin-1)', + 'ISO-8859-2' => 'ISO-8895-2 (Central European)', + 'ISO-8859-7' => 'ISO-8859-7 (Greek)', + 'ISO-8859-9' => 'ISO-8859-9 (Turkish)', + 'Windows-1251' => 'Windows-1251 (Cyrillic)', + 'Windows-1252' => 'Windows-1252 (Western)', + 'Windows-1255' => 'Windows-1255 (Hebrew)', + 'Windows-1256' => 'Windows-1256 (Arabic)', + 'Windows-1257' => 'Windows-1257 (Baltic)', + 'UTF-8' => 'UTF-8' + ); + + $select = new html_select($field_attrib); + $select->add(array_values($charsets), array_keys($charsets)); + + $set = $_POST['_charset'] ? $_POST['_charset'] : $this->get_charset(); + return $select->show($set); + } + +} // end class rcube_template + + diff --git a/program/include/rcube_user.inc b/program/include/rcube_user.inc deleted file mode 100644 index e748758..0000000 --- a/program/include/rcube_user.inc +++ /dev/null @@ -1,482 +0,0 @@ - | - +-----------------------------------------------------------------------+ - - $Id: rcube_user.inc 933 2007-11-29 14:17:32Z thomasb $ - -*/ - - -/** - * Class representing a system user - * - * @package core - * @author Thomas Bruederli - */ -class rcube_user -{ - var $ID = null; - var $data = null; - - - /** - * Object constructor - * - * @param object DB Database connection - */ - function __construct($id = null, $sql_arr = null) - { - global $DB; - - if ($id && !$sql_arr) - { - $sql_result = $DB->query("SELECT * FROM ".get_table_name('users')." WHERE user_id=?", $id); - $sql_arr = $DB->fetch_assoc($sql_result); - } - - if (!empty($sql_arr)) - { - $this->ID = $sql_arr['user_id']; - $this->data = $sql_arr; - } - } - - /** - * PHP 4 object constructor - * - * @see rcube_user::__construct - */ - function rcube_user($id = null, $sql_arr = null) - { - $this->__construct($id, $sql_arr); - } - - - /** - * Build a user name string (as e-mail address) - * - * @return string Full user name - */ - function get_username() - { - return $this->data['username'] ? $this->data['username'] . (!strpos($this->data['username'], '@') ? '@'.$this->data['mail_host'] : '') : false; - } - - - /** - * Get the preferences saved for this user - * - * @return array Hash array with prefs - */ - function get_prefs() - { - if ($this->ID && $this->data['preferences']) - return unserialize($this->data['preferences']); - else - return array(); - } - - - /** - * Write the given user prefs to the user's record - * - * @param mixed User prefs to save - * @return boolean True on success, False on failure - */ - function save_prefs($a_user_prefs) - { - global $DB, $CONFIG, $sess_user_lang; - - if (!$this->ID) - return false; - - // merge (partial) prefs array with existing settings - $a_user_prefs += (array)$this->get_prefs(); - - $DB->query( - "UPDATE ".get_table_name('users')." - SET preferences=?, - language=? - WHERE user_id=?", - serialize($a_user_prefs), - $sess_user_lang, - $this->ID); - - if ($DB->affected_rows()) - { - $CONFIG = array_merge($CONFIG, $a_user_prefs); - return true; - } - - return false; - } - - - /** - * Get default identity of this user - * - * @param int Identity ID. If empty, the default identity is returned - * @return array Hash array with all cols of the - */ - function get_identity($id = null) - { - global $DB; - - $sql_result = $this->list_identities($id ? sprintf('AND identity_id=%d', $id) : ''); - return $DB->fetch_assoc($sql_result); - } - - - /** - * Return a list of all identities linked with this user - * - * @return array List of identities - */ - function list_identities($sql_add = '') - { - global $DB; - - // get contacts from DB - $sql_result = $DB->query( - "SELECT * FROM ".get_table_name('identities')." - WHERE del<>1 - AND user_id=? - $sql_add - ORDER BY ".$DB->quoteIdentifier('standard')." DESC, name ASC", - $this->ID); - - return $sql_result; - } - - - /** - * Update a specific identity record - * - * @param int Identity ID - * @param array Hash array with col->value pairs to save - * @return boolean True if saved successfully, false if nothing changed - */ - function update_identity($iid, $data) - { - global $DB; - - if (!$this->ID) - return false; - - $write_sql = array(); - - foreach ((array)$data as $col => $value) - { - $write_sql[] = sprintf("%s=%s", - $DB->quoteIdentifier($col), - $DB->quote($value)); - } - - $DB->query( - "UPDATE ".get_table_name('identities')." - SET ".join(', ', $write_sql)." - WHERE identity_id=? - AND user_id=? - AND del<>1", - $iid, - $this->ID); - - return $DB->affected_rows(); - } - - - /** - * Create a new identity record linked with this user - * - * @param array Hash array with col->value pairs to save - * @return int The inserted identity ID or false on error - */ - function insert_identity($data) - { - global $DB; - - if (!$this->ID) - return false; - - $insert_cols = $insert_values = array(); - foreach ((array)$data as $col => $value) - { - $insert_cols[] = $DB->quoteIdentifier($col); - $insert_values[] = $DB->quote($value); - } - - $DB->query( - "INSERT INTO ".get_table_name('identities')." - (user_id, ".join(', ', $insert_cols).") - VALUES (?, ".join(', ', $insert_values).")", - $this->ID); - - return $DB->insert_id(get_sequence_name('identities')); - } - - - /** - * Mark the given identity as deleted - * - * @param int Identity ID - * @return boolean True if deleted successfully, false if nothing changed - */ - function delete_identity($iid) - { - global $DB; - - if (!$this->ID) - return false; - - if (!$this->ID || $this->ID == '') - return false; - - $sql_result = $DB->query("SELECT count(*) AS ident_count FROM " . - get_table_name('identities') . - " WHERE user_id = ? AND del <> 1", - $this->ID); - - $sql_arr = $DB->fetch_assoc($sql_result); - if ($sql_arr['ident_count'] <= 1) - return false; - - $DB->query( - "UPDATE ".get_table_name('identities')." - SET del=1 - WHERE user_id=? - AND identity_id=?", - $this->ID, - $iid); - - return $DB->affected_rows(); - } - - - /** - * Make this identity the default one for this user - * - * @param int The identity ID - */ - function set_default($iid) - { - global $DB; - - if ($this->ID && $iid) - { - $DB->query( - "UPDATE ".get_table_name('identities')." - SET ".$DB->quoteIdentifier('standard')."='0' - WHERE user_id=? - AND identity_id<>? - AND del<>1", - $this->ID, - $iid); - } - } - - - /** - * Update user's last_login timestamp - */ - function touch() - { - global $DB; - - if ($this->ID) - { - $DB->query( - "UPDATE ".get_table_name('users')." - SET last_login=".$DB->now()." - WHERE user_id=?", - $this->ID); - } - } - - - /** - * Clear the saved object state - */ - function reset() - { - $this->ID = null; - $this->data = null; - } - - - /** - * Find a user record matching the given name and host - * - * @param string IMAP user name - * @param string IMAP host name - * @return object rcube_user New user instance - * @static - */ - function query($user, $host) - { - global $DB; - - // query if user already registered - $sql_result = $DB->query( - "SELECT * FROM ".get_table_name('users')." - WHERE mail_host=? AND (username=? OR alias=?)", - $host, - $user, - $user); - - // user already registered -> overwrite username - if ($sql_arr = $DB->fetch_assoc($sql_result)) - return new rcube_user($sql_arr['user_id'], $sql_arr); - else - return false; - } - - - /** - * Create a new user record and return a rcube_user instance - * - * @param string IMAP user name - * @param string IMAP host - * @return object rcube_user New user instance - * @static - */ - function create($user, $host) - { - global $DB, $CONFIG; - - $user_email = ''; - - // try to resolve user in virtusertable - if (!empty($CONFIG['virtuser_file']) && !strpos($user, '@')) - $user_email = rcube_user::user2email($user); - - $DB->query( - "INSERT INTO ".get_table_name('users')." - (created, last_login, username, mail_host, alias, language) - VALUES (".$DB->now().", ".$DB->now().", ?, ?, ?, ?)", - strip_newlines($user), - strip_newlines($host), - strip_newlines($user_email), - $_SESSION['user_lang']); - - if ($user_id = $DB->insert_id(get_sequence_name('users'))) - { - $mail_domain = rcmail_mail_domain($host); - - if ($user_email=='') - $user_email = strpos($user, '@') ? $user : sprintf('%s@%s', $user, $mail_domain); - - $user_name = $user != $user_email ? $user : ''; - - // try to resolve the e-mail address from the virtuser table - if (!empty($CONFIG['virtuser_query']) && - ($sql_result = $DB->query(preg_replace('/%u/', $DB->escapeSimple($user), $CONFIG['virtuser_query']))) && - ($DB->num_rows()>0)) - { - while ($sql_arr = $DB->fetch_array($sql_result)) - { - $DB->query( - "INSERT INTO ".get_table_name('identities')." - (user_id, del, standard, name, email) - VALUES (?, 0, 1, ?, ?)", - $user_id, - strip_newlines($user_name), - preg_replace('/^@/', $user . '@', $sql_arr[0])); - } - } - else - { - // also create new identity records - $DB->query( - "INSERT INTO ".get_table_name('identities')." - (user_id, del, standard, name, email) - VALUES (?, 0, 1, ?, ?)", - $user_id, - strip_newlines($user_name), - strip_newlines($user_email)); - } - } - else - { - raise_error(array( - 'code' => 500, - 'type' => 'php', - 'line' => __LINE__, - 'file' => __FILE__, - 'message' => "Failed to create new user"), true, false); - } - - return $user_id ? new rcube_user($user_id) : false; - } - - - /** - * Resolve username using a virtuser table - * - * @param string E-mail address to resolve - * @return string Resolved IMAP username - * @static - */ - function email2user($email) - { - $user = $email; - $r = rcmail_findinvirtual("^$email"); - - for ($i=0; $i 0) - { - $user = trim($arr[count($arr)-1]); - break; - } - } - - return $user; - } - - - /** - * Resolve e-mail address from virtuser table - * - * @param string User name - * @return string Resolved e-mail address - * @static - */ - function user2email($user) - { - $email = ""; - $r = rcmail_findinvirtual("$user$"); - - for ($i=0; $i 0) - { - $email = trim(str_replace('\\@', '@', $arr[0])); - break; - } - } - - return $email; - } - -} - - -?> diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php new file mode 100644 index 0000000..c808d07 --- /dev/null +++ b/program/include/rcube_user.php @@ -0,0 +1,467 @@ + | + +-----------------------------------------------------------------------+ + + $Id: rcube_user.inc 933 2007-11-29 14:17:32Z thomasb $ + +*/ + + +/** + * Class representing a system user + * + * @package Core + * @author Thomas Bruederli + */ +class rcube_user +{ + public $ID = null; + public $data = null; + public $language = 'en_US'; + + private $db = null; + + + /** + * Object constructor + * + * @param object DB Database connection + */ + function __construct($id = null, $sql_arr = null) + { + $this->db = rcmail::get_instance()->get_dbh(); + + if ($id && !$sql_arr) + { + $sql_result = $this->db->query("SELECT * FROM ".get_table_name('users')." WHERE user_id=?", $id); + $sql_arr = $this->db->fetch_assoc($sql_result); + } + + if (!empty($sql_arr)) + { + $this->ID = $sql_arr['user_id']; + $this->data = $sql_arr; + $this->language = $sql_arr['language']; + } + } + + /** + * PHP 4 object constructor + * + * @see rcube_user::__construct + */ + function rcube_user($id = null, $sql_arr = null) + { + $this->__construct($id, $sql_arr); + } + + + /** + * Build a user name string (as e-mail address) + * + * @return string Full user name + */ + function get_username() + { + return $this->data['username'] ? $this->data['username'] . (!strpos($this->data['username'], '@') ? '@'.$this->data['mail_host'] : '') : false; + } + + + /** + * Get the preferences saved for this user + * + * @return array Hash array with prefs + */ + function get_prefs() + { + if ($this->ID && $this->data['preferences']) + return array('language' => $this->language) + unserialize($this->data['preferences']); + else + return array(); + } + + + /** + * Write the given user prefs to the user's record + * + * @param mixed User prefs to save + * @return boolean True on success, False on failure + */ + function save_prefs($a_user_prefs) + { + if (!$this->ID) + return false; + + // merge (partial) prefs array with existing settings + $a_user_prefs += (array)$this->get_prefs(); + unset($a_user_prefs['language']); + + $this->db->query( + "UPDATE ".get_table_name('users')." + SET preferences=?, + language=? + WHERE user_id=?", + serialize($a_user_prefs), + $_SESSION['language'], + $this->ID); + + $this->language = $_SESSION['language']; + if ($this->db->affected_rows()) + { + rcmail::get_instance()->config->merge($a_user_prefs); + return true; + } + + return false; + } + + + /** + * Get default identity of this user + * + * @param int Identity ID. If empty, the default identity is returned + * @return array Hash array with all cols of the + */ + function get_identity($id = null) + { + $sql_result = $this->list_identities($id ? sprintf('AND identity_id=%d', $id) : ''); + return $this->db->fetch_assoc($sql_result); + } + + + /** + * Return a list of all identities linked with this user + * + * @return array List of identities + */ + function list_identities($sql_add = '') + { + // get contacts from DB + $sql_result = $this->db->query( + "SELECT * FROM ".get_table_name('identities')." + WHERE del<>1 + AND user_id=? + $sql_add + ORDER BY ".$this->db->quoteIdentifier('standard')." DESC, name ASC", + $this->ID); + + return $sql_result; + } + + + /** + * Update a specific identity record + * + * @param int Identity ID + * @param array Hash array with col->value pairs to save + * @return boolean True if saved successfully, false if nothing changed + */ + function update_identity($iid, $data) + { + if (!$this->ID) + return false; + + $write_sql = array(); + + foreach ((array)$data as $col => $value) + { + $write_sql[] = sprintf("%s=%s", + $this->db->quoteIdentifier($col), + $this->db->quote($value)); + } + + $this->db->query( + "UPDATE ".get_table_name('identities')." + SET ".join(', ', $write_sql)." + WHERE identity_id=? + AND user_id=? + AND del<>1", + $iid, + $this->ID); + + return $this->db->affected_rows(); + } + + + /** + * Create a new identity record linked with this user + * + * @param array Hash array with col->value pairs to save + * @return int The inserted identity ID or false on error + */ + function insert_identity($data) + { + if (!$this->ID) + return false; + + $insert_cols = $insert_values = array(); + foreach ((array)$data as $col => $value) + { + $insert_cols[] = $this->db->quoteIdentifier($col); + $insert_values[] = $this->db->quote($value); + } + + $this->db->query( + "INSERT INTO ".get_table_name('identities')." + (user_id, ".join(', ', $insert_cols).") + VALUES (?, ".join(', ', $insert_values).")", + $this->ID); + + return $this->db->insert_id(get_sequence_name('identities')); + } + + + /** + * Mark the given identity as deleted + * + * @param int Identity ID + * @return boolean True if deleted successfully, false if nothing changed + */ + function delete_identity($iid) + { + if (!$this->ID) + return false; + + if (!$this->ID || $this->ID == '') + return false; + + $sql_result = $this->db->query("SELECT count(*) AS ident_count FROM " . + get_table_name('identities') . + " WHERE user_id = ? AND del <> 1", + $this->ID); + + $sql_arr = $this->db->fetch_assoc($sql_result); + if ($sql_arr['ident_count'] <= 1) + return false; + + $this->db->query( + "UPDATE ".get_table_name('identities')." + SET del=1 + WHERE user_id=? + AND identity_id=?", + $this->ID, + $iid); + + return $this->db->affected_rows(); + } + + + /** + * Make this identity the default one for this user + * + * @param int The identity ID + */ + function set_default($iid) + { + if ($this->ID && $iid) + { + $this->db->query( + "UPDATE ".get_table_name('identities')." + SET ".$this->db->quoteIdentifier('standard')."='0' + WHERE user_id=? + AND identity_id<>? + AND del<>1", + $this->ID, + $iid); + } + } + + + /** + * Update user's last_login timestamp + */ + function touch() + { + if ($this->ID) + { + $this->db->query( + "UPDATE ".get_table_name('users')." + SET last_login=".$this->db->now()." + WHERE user_id=?", + $this->ID); + } + } + + + /** + * Clear the saved object state + */ + function reset() + { + $this->ID = null; + $this->data = null; + } + + + /** + * Find a user record matching the given name and host + * + * @param string IMAP user name + * @param string IMAP host name + * @return object rcube_user New user instance + */ + static function query($user, $host) + { + $dbh = rcmail::get_instance()->get_dbh(); + + // query if user already registered + $sql_result = $dbh->query( + "SELECT * FROM ".get_table_name('users')." + WHERE mail_host=? AND (username=? OR alias=?)", + $host, + $user, + $user); + + // user already registered -> overwrite username + if ($sql_arr = $dbh->fetch_assoc($sql_result)) + return new rcube_user($sql_arr['user_id'], $sql_arr); + else + return false; + } + + + /** + * Create a new user record and return a rcube_user instance + * + * @param string IMAP user name + * @param string IMAP host + * @return object rcube_user New user instance + */ + static function create($user, $host) + { + $user_email = ''; + $rcmail = rcmail::get_instance(); + $dbh = $rcmail->get_dbh(); + + // try to resolve user in virtusertable + if ($rcmail->config->get('virtuser_file') && !strpos($user, '@')) + $user_email = rcube_user::user2email($user); + + $dbh->query( + "INSERT INTO ".get_table_name('users')." + (created, last_login, username, mail_host, alias, language) + VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?, ?)", + strip_newlines($user), + strip_newlines($host), + strip_newlines($user_email), + $_SESSION['language']); + + if ($user_id = $dbh->insert_id(get_sequence_name('users'))) + { + $mail_domain = rcmail_mail_domain($host); + + if ($user_email=='') + $user_email = strpos($user, '@') ? $user : sprintf('%s@%s', $user, $mail_domain); + + $user_name = $user != $user_email ? $user : ''; + + // try to resolve the e-mail address from the virtuser table + if ($virtuser_query = $rcmail->config->get('virtuser_query') && + ($sql_result = $dbh->query(preg_replace('/%u/', $dbh->escapeSimple($user), $virtuser_query))) && + ($dbh->num_rows() > 0)) + { + while ($sql_arr = $dbh->fetch_array($sql_result)) + { + $dbh->query( + "INSERT INTO ".get_table_name('identities')." + (user_id, del, standard, name, email) + VALUES (?, 0, 1, ?, ?)", + $user_id, + strip_newlines($user_name), + preg_replace('/^@/', $user . '@', $sql_arr[0])); + } + } + else + { + // also create new identity records + $dbh->query( + "INSERT INTO ".get_table_name('identities')." + (user_id, del, standard, name, email) + VALUES (?, 0, 1, ?, ?)", + $user_id, + strip_newlines($user_name), + strip_newlines($user_email)); + } + } + else + { + raise_error(array( + 'code' => 500, + 'type' => 'php', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => "Failed to create new user"), true, false); + } + + return $user_id ? new rcube_user($user_id) : false; + } + + + /** + * Resolve username using a virtuser table + * + * @param string E-mail address to resolve + * @return string Resolved IMAP username + */ + static function email2user($email) + { + $user = $email; + $r = rcmail_findinvirtual("^$email"); + + for ($i=0; $i 0) + { + $user = trim($arr[count($arr)-1]); + break; + } + } + + return $user; + } + + + /** + * Resolve e-mail address from virtuser table + * + * @param string User name + * @return string Resolved e-mail address + */ + static function user2email($user) + { + $email = ""; + $r = rcmail_findinvirtual("$user$"); + + for ($i=0; $i 0) + { + $email = trim(str_replace('\\@', '@', $arr[0])); + break; + } + } + + return $email; + } + +} + + diff --git a/program/include/session.inc b/program/include/session.inc index 6b0eeab..60ae9e1 100644 --- a/program/include/session.inc +++ b/program/include/session.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: session.inc 1063 2008-02-13 05:26:47Z till $ + $Id: session.inc 1400 2008-05-17 17:46:43Z thomasb $ */ @@ -26,7 +26,6 @@ function sess_open($save_path, $session_name) } - function sess_close() { return TRUE; @@ -89,9 +88,7 @@ function sess_write($key, $vars) VALUES (?, ?, ?, ".$DB->now().", ".$DB->now().")", $key, $vars, - $_SERVER['REMOTE_ADDR']); - - + (string)$_SERVER['REMOTE_ADDR']); } return TRUE; @@ -101,15 +98,18 @@ function sess_write($key, $vars) // handler for session_destroy() function sess_destroy($key) { - global $DB; + global $DB, $CONFIG; if ($DB->is_error()) return FALSE; - - // delete session entries in cache table - $DB->query("DELETE FROM ".get_table_name('cache')." - WHERE session_id=?", + + if ($CONFIG['enable_caching']) + { + // delete session entries in cache table + $DB->query("DELETE FROM ".get_table_name('cache')." + WHERE session_id=?", $key); + } $DB->query("DELETE FROM ".get_table_name('session')." WHERE sess_id=?", @@ -122,7 +122,7 @@ function sess_destroy($key) // garbage collecting function function sess_gc($maxlifetime) { - global $DB; + global $DB, $CONFIG; if ($DB->is_error()) return FALSE; @@ -137,20 +137,23 @@ function sess_gc($maxlifetime) while ($sql_arr = $DB->fetch_assoc($sql_result)) $a_exp_sessions[] = $sql_arr['sess_id']; - if (sizeof($a_exp_sessions)) { - // delete session cache records - $DB->query("DELETE FROM ".get_table_name('cache')." - WHERE session_id IN ('".join("','", $a_exp_sessions)."')"); - + if ($CONFIG['enable_caching']) + { + // delete session cache records + $DB->query("DELETE FROM ".get_table_name('cache')." + WHERE session_id IN ('".join("','", $a_exp_sessions)."')"); + } + // delete session records $DB->query("DELETE FROM ".get_table_name('session')." WHERE sess_id IN ('".join("','", $a_exp_sessions)."')"); } // also run message cache GC - rcmail_message_cache_gc(); + if ($CONFIG['enable_caching']) + rcmail_message_cache_gc(); rcmail_temp_gc(); return TRUE; diff --git a/program/js/app.js b/program/js/app.js index 1ddb6da..de250c5 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -13,7 +13,7 @@ | Requires: common.js, list.js | +-----------------------------------------------------------------------+ - $Id: app.js 1255 2008-04-05 12:49:21Z thomasb $ + $Id: app.js 1464 2008-06-02 12:24:31Z alec $ */ @@ -179,7 +179,6 @@ function rcube_webmail() { this.enable_command('compose', 'add-contact', false); parent.rcmail.show_contentframe(true); - parent.rcmail.mark_message('read', this.env.uid); } if ((this.env.action=='show' || this.env.action=='preview') && this.env.blockedobjects) @@ -356,7 +355,7 @@ function rcube_webmail() // start interval for keep-alive/recent_check signal this.start_keepalive = function() { - if (this.env.keep_alive && !this.env.framed && this.task=='mail' && this.gui_objects.messagelist) + if (this.env.keep_alive && !this.env.framed && this.task=='mail' && this.gui_objects.mailboxlist) this._int = setInterval(function(){ ref.check_for_recent(); }, this.env.keep_alive * 1000); else if (this.env.keep_alive && !this.env.framed && this.task!='login') this._int = setInterval(function(){ ref.send_keep_alive(); }, this.env.keep_alive * 1000); @@ -406,7 +405,7 @@ function rcube_webmail() this.init_address_input_events(input_cc); if (input_bcc) this.init_address_input_events(input_bcc); - + // add signature according to selected identity if (input_from && input_from.type=='select-one') this.change_identity(input_from); @@ -488,7 +487,7 @@ function rcube_webmail() break; case 'logout': - this.goto_url('logout', true); + this.goto_url('logout', '', true); break; // commands to switch task @@ -631,7 +630,7 @@ function rcube_webmail() var input_email = rcube_find_object('_email'); // user prefs - if (input_pagesize && isNaN(input_pagesize.value)) + if (input_pagesize && isNaN(parseInt(input_pagesize.value))) { alert(this.get_label('nopagesizewarning')); input_pagesize.focus(); @@ -722,7 +721,7 @@ function rcube_webmail() this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment'); if (this.attachment_win) { - setTimeout(function(){ ref.attachment_win.focus(); }, 10); + window.setTimeout(function(){ ref.attachment_win.focus(); }, 10); break; } } @@ -890,7 +889,7 @@ function rcube_webmail() ref.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : '')); if (this.printwin) { - setTimeout(function(){ ref.printwin.focus(); }, 20); + window.setTimeout(function(){ ref.printwin.focus(); }, 20); if (this.env.action != 'show') this.mark_message('read', uid); } @@ -903,7 +902,7 @@ function rcube_webmail() { ref.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox)); if (this.sourcewin) - setTimeout(function(){ ref.sourcewin.focus(); }, 20); + window.setTimeout(function(){ ref.sourcewin.focus(); }, 20); } break; @@ -1020,7 +1019,7 @@ function rcube_webmail() // set timer for requests if (a && this.env.request_timeout) - this.request_timer = setTimeout(function(){ ref.request_timed_out(); }, this.env.request_timeout * 1000); + this.request_timer = window.setTimeout(function(){ ref.request_timed_out(); }, this.env.request_timeout * 1000); }; @@ -1139,7 +1138,7 @@ function rcube_webmail() // start timer for message preview (wait for double click) if (selected && this.env.contentframe && !list.multi_selecting) - this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, this.dblclick_time + 10); + this.preview_timer = window.setTimeout(function(){ ref.msglist_get_preview(); }, this.dblclick_time + 10); else if (this.env.contentframe) this.show_contentframe(false); }; @@ -1233,9 +1232,12 @@ function rcube_webmail() var frm; if (this.env.contentframe && (frm = rcube_find_object(this.env.contentframe))) { - if (!show && window.frames[this.env.contentframe] && frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)<0) - frames[this.env.contentframe].location.href = this.env.blankpage; - if (!bw.safari) + if (!show && window.frames[this.env.contentframe]) + { + if (window.frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)<0) + window.frames[this.env.contentframe].location.href = this.env.blankpage; + } + else if (!bw.safari) frm.style.display = show ? 'block' : 'none'; } @@ -1408,7 +1410,7 @@ function rcube_webmail() this.delete_messages = function() { var selection = this.message_list ? this.message_list.get_selection() : new Array(); - + // exit if no mailbox specified or if selection is empty if (!this.env.uid && !selection.length) return; @@ -1459,8 +1461,9 @@ function rcube_webmail() this._with_selected_messages = function(action, lock, add_url) { var a_uids = new Array(); + if (this.env.uid) - a_uids[a_uids.length] = this.env.uid; + a_uids[0] = this.env.uid; else { var selection = this.message_list.get_selection(); @@ -1469,10 +1472,11 @@ function rcube_webmail() { id = selection[n]; a_uids[a_uids.length] = id; + this.message_list.remove_row(id, (n == selection.length-1)); } } - + // also send search request to get the right messages if (this.env.search_request) add_url += '&_search='+this.env.search_request; @@ -1488,20 +1492,23 @@ function rcube_webmail() var a_uids = new Array(); var r_uids = new Array(); var selection = this.message_list ? this.message_list.get_selection() : new Array(); - + if (uid) a_uids[0] = uid; else if (this.env.uid) a_uids[0] = this.env.uid; else if (this.message_list) { - for (var id, n=0; n