summaryrefslogtreecommitdiff
path: root/program/include
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2005-12-03 16:54:12 +0000
committerthomascube <thomas@roundcube.net>2005-12-03 16:54:12 +0000
commit1cded85790206afe084e1baff371c543711b2b18 (patch)
treeb050fb89707e048df5f30f500faad792962a1e81 /program/include
parent5bc8cb662fc3bcda9aa641b7a5e88c0b81dd63d6 (diff)
Re-design of caching (new database table added\!); some bugfixes; Postgres support
Diffstat (limited to 'program/include')
-rw-r--r--program/include/cache.inc5
-rw-r--r--program/include/main.inc312
-rwxr-xr-xprogram/include/rcube_db.inc465
-rw-r--r--program/include/rcube_imap.inc748
-rwxr-xr-xprogram/include/rcube_mdb2.inc16
-rw-r--r--program/include/rcube_shared.inc109
-rw-r--r--program/include/rcube_sqlite.inc71
-rw-r--r--program/include/session.inc16
8 files changed, 1107 insertions, 635 deletions
diff --git a/program/include/cache.inc b/program/include/cache.inc
index 8d088e57b..06e0681ce 100644
--- a/program/include/cache.inc
+++ b/program/include/cache.inc
@@ -43,8 +43,8 @@ function rcube_read_cache($key)
return $data;
}
-
-
+
+
function rcube_write_cache($key, $data, $session_cache=FALSE)
{
global $DB, $CACHE_KEYS, $sess_id;
@@ -91,7 +91,6 @@ function rcube_write_cache($key, $data, $session_cache=FALSE)
}
-
function rcube_clear_cache($key)
{
global $DB;
diff --git a/program/include/main.inc b/program/include/main.inc
index ddb42181a..40ca1d4d7 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -69,7 +69,7 @@ function rcmail_startup($task='mail')
// we can use the database for storing session data
// session queries do not work with MDB2
- if ($CONFIG['db_backend']!='mdb2' && is_object($DB) && $DB->db_provider!='sqlite')
+ if ($CONFIG['db_backend']!='mdb2' && is_object($DB) /* && $DB->db_provider!='sqlite' */)
include_once('include/session.inc');
@@ -143,9 +143,9 @@ function rcmail_auth_hash($sess_id, $ts)
// create IMAP object and connect to server
function rcmail_imap_init($connect=FALSE)
{
- global $CONFIG, $IMAP;
+ global $CONFIG, $DB, $IMAP;
- $IMAP = new rcube_imap();
+ $IMAP = new rcube_imap($DB);
// connect with stored session data
if ($connect)
@@ -227,6 +227,22 @@ function get_table_name($table)
}
+// return correct name for a specific database sequence
+// (used for Postres only)
+function get_sequence_name($sequence)
+ {
+ global $CONFIG;
+
+ // return table name if configured
+ $config_key = 'db_sequence_'.$sequence;
+
+ if (strlen($CONFIG[$config_key]))
+ return $CONFIG[$config_key];
+
+ return $table;
+ }
+
+
// init output object for GUI and add common scripts
function load_gui()
@@ -380,15 +396,15 @@ function rcmail_create_user($user, $host)
$host,
$_SESSION['user_lang']);
- if ($user_id = $DB->insert_id('user_ids'))
+ if ($user_id = $DB->insert_id(get_sequence_name('users')))
{
$user_email = strstr($user, '@') ? $user : sprintf('%s@%s', $user, $host);
$user_name = $user!=$user_email ? $user : '';
// also create a new identity record
$DB->query("INSERT INTO ".get_table_name('identities')."
- (user_id, `default`, name, email)
- VALUES (?, '1', ?, ?)",
+ (user_id, del, standard, name, email)
+ VALUES (?, 0, 1, ?, ?)",
$user_id,
$user_name,
$user_email);
@@ -479,7 +495,6 @@ function decrypt_passwd($cypher)
function rcube_remote_response($js_code)
{
send_nocacheing_headers();
- //header('Content-Type: text/javascript');
header('Content-Type: application/x-javascript');
print '/** remote response ['.date('d/M/Y h:i:s O')."] **/\n";
@@ -530,6 +545,117 @@ function rcube_add_label()
}
+// remove temp files of a session
+function rcmail_clear_session_temp($sess_id)
+ {
+ global $CONFIG;
+
+ $temp_dir = $CONFIG['temp_dir'].(!eregi('\/$', $CONFIG['temp_dir']) ? '/' : '');
+ $cache_dir = $temp_dir.$sess_id;
+
+ if (is_dir($cache_dir))
+ {
+ clear_directory($cache_dir);
+ rmdir($cache_dir);
+ }
+ }
+
+
+
+// replace specials characters to a specific encoding type
+function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
+ {
+ global $OUTPUT_TYPE, $CHARSET;
+ static $html_encode_arr, $js_rep_table, $rtf_rep_table, $xml_rep_table;
+
+ if (!$enctype)
+ $enctype = $GLOBALS['OUTPUT_TYPE'];
+
+ // convert nbsps back to normal spaces if not html
+ if ($enctype!='html')
+ $str = str_replace(chr(160), ' ', $str);
+
+
+ // encode for plaintext
+ if ($enctype=='text')
+ return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
+
+ // encode for HTML output
+ if ($enctype=='html')
+ {
+ if (!$html_encode_arr)
+ {
+ if ($CHARSET=='ISO-8859-1')
+ {
+ $html_encode_arr = get_html_translation_table(HTML_ENTITIES);
+ $html_encode_arr[chr(128)] = '&euro;';
+ }
+ else
+ $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
+
+ unset($html_encode_arr['?']);
+ unset($html_encode_arr['&']);
+ }
+
+ $ltpos = strpos($str, '<');
+ $encode_arr = $html_encode_arr;
+
+ // don't replace quotes and html tags
+ if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false)
+ {
+ unset($encode_arr['"']);
+ unset($encode_arr['<']);
+ unset($encode_arr['>']);
+ }
+ else if ($mode=='remove')
+ $str = strip_tags($str);
+
+ $out = strtr($str, $encode_arr);
+
+ return $newlines ? nl2br($out) : $out;
+ }
+
+
+ if ($enctype=='url')
+ return rawurlencode($str);
+
+
+ // if the replace tables for RTF, XML and JS are not yet defined
+ if (!$js_rep_table)
+ {
+ $js_rep_table = $rtf_rep_table = $xml_rep_table = array();
+
+ for ($c=160; $c<256; $c++) // can be increased to support more charsets
+ {
+ $hex = dechex($c);
+ $rtf_rep_table[Chr($c)] = "\\'$hex";
+ $xml_rep_table[Chr($c)] = "&#$c;";
+
+ if ($CHARSET=='ISO-8859-1')
+ $js_rep_table[Chr($c)] = sprintf("\u%s%s", str_repeat('0', 4-strlen($hex)), $hex);
+ }
+
+ $js_rep_table['"'] = sprintf("\u%s%s", str_repeat('0', 4-strlen(dechex(34))), dechex(34));
+ $xml_rep_table['"'] = '&quot;';
+ }
+
+ // encode for RTF
+ if ($enctype=='xml')
+ return strtr($str, $xml_rep_table);
+
+ // encode for javascript use
+ if ($enctype=='js')
+ return preg_replace(array("/\r\n/", '/"/', "/([^\\\])'/"), array('\n', '\"', "$1\'"), strtr($str, $js_rep_table));
+
+ // encode for RTF
+ if ($enctype=='rtf')
+ return preg_replace("/\r\n/", "\par ", strtr($str, $rtf_rep_table));
+
+ // no encoding given -> return original string
+ return $str;
+ }
+
+
// ************** template parsing and gui functions **************
@@ -653,104 +779,53 @@ function rcube_xml_command($command, $str_attrib, $a_attrib=NULL)
case 'object':
$object = strtolower($attrib['name']);
+ $object_handlers = array(
+ // MAIL
+ 'mailboxlist' => 'rcmail_mailbox_list',
+ 'messages' => 'rcmail_message_list',
+ 'messagecountdisplay' => 'rcmail_messagecount_display',
+ 'messageheaders' => 'rcmail_message_headers',
+ 'messagebody' => 'rcmail_message_body',
+ 'messageattachments' => 'rcmail_message_attachments',
+ 'blockedobjects' => 'rcmail_remote_objects_msg',
+ 'messagecontentframe' => 'rcmail_messagecontent_frame',
+ 'messagepartframe' => 'rcmail_message_part_frame',
+ 'messagepartcontrols' => 'rcmail_message_part_controls',
+ 'composeheaders' => 'rcmail_compose_headers',
+ 'composesubject' => 'rcmail_compose_subject',
+ 'composebody' => 'rcmail_compose_body',
+ 'composeattachmentlist' => 'rcmail_compose_attachment_list',
+ 'composeattachmentform' => 'rcmail_compose_attachment_form',
+ 'composeattachment' => 'rcmail_compose_attachment_field',
+ 'priorityselector' => 'rcmail_priority_selector',
+ 'charsetselector' => 'rcmail_charset_selector',
+
+ // ADDRESS BOOK
+ 'addresslist' => 'rcmail_contacts_list',
+ 'addressframe' => 'rcmail_contact_frame',
+ 'recordscountdisplay' => 'rcmail_rowcount_display',
+ 'contactdetails' => 'rcmail_contact_details',
+ 'contacteditform' => 'rcmail_contact_editform',
+
+ // USER SETTINGS
+ 'userprefs' => 'rcmail_user_prefs_form',
+ 'itentitieslist' => 'rcmail_identities_list',
+ 'identityframe' => 'rcmail_identity_frame',
+ 'identityform' => 'rcube_identity_form',
+ 'foldersubscription' => 'rcube_subscription_form',
+ 'createfolder' => 'rcube_create_folder_form',
+ 'composebody' => 'rcmail_compose_body'
+ );
+
if ($object=='loginform')
return rcmail_login_form($attrib);
else if ($object=='message')
return rcmail_message_container($attrib);
-
- // MAIL
- else if ($object=='mailboxlist' && function_exists('rcmail_mailbox_list'))
- return rcmail_mailbox_list($attrib);
-
- else if ($object=='messages' && function_exists('rcmail_message_list'))
- return rcmail_message_list($attrib);
-
- else if ($object=='messagecountdisplay' && function_exists('rcmail_messagecount_display'))
- return rcmail_messagecount_display($attrib);
-
- else if ($object=='messageheaders' && function_exists('rcmail_message_headers'))
- return rcmail_message_headers($attrib);
-
- else if ($object=='messageattachments' && function_exists('rcmail_message_attachments'))
- return rcmail_message_attachments($attrib);
-
- else if ($object=='messagebody' && function_exists('rcmail_message_body'))
- return rcmail_message_body($attrib);
-
- else if ($object=='blockedobjects' && function_exists('rcmail_remote_objects_msg'))
- return rcmail_remote_objects_msg($attrib);
-
- else if ($object=='messagecontentframe' && function_exists('rcmail_messagecontent_frame'))
- return rcmail_messagecontent_frame($attrib);
-
- else if ($object=='messagepartframe' && function_exists('rcmail_message_part_frame'))
- return rcmail_message_part_frame($attrib);
-
- else if ($object=='messagepartcontrols' && function_exists('rcmail_message_part_controls'))
- return rcmail_message_part_controls($attrib);
-
- else if ($object=='composeheaders' && function_exists('rcmail_compose_headers'))
- return rcmail_compose_headers($attrib);
-
- else if ($object=='composesubject' && function_exists('rcmail_compose_subject'))
- return rcmail_compose_subject($attrib);
-
- else if ($object=='composebody' && function_exists('rcmail_compose_body'))
- return rcmail_compose_body($attrib);
-
- else if ($object=='composeattachmentlist' && function_exists('rcmail_compose_attachment_list'))
- return rcmail_compose_attachment_list($attrib);
-
- else if ($object=='composeattachmentform' && function_exists('rcmail_compose_attachment_form'))
- return rcmail_compose_attachment_form($attrib);
-
- else if ($object=='composeattachment' && function_exists('rcmail_compose_attachment_field'))
- return rcmail_compose_attachment_field($attrib);
-
- else if ($object=='priorityselector' && function_exists('rcmail_priority_selector'))
- return rcmail_priority_selector($attrib);
-
- else if ($object=='priorityselector' && function_exists('rcmail_priority_selector'))
- return rcmail_priority_selector($attrib);
-
-
- // ADDRESS BOOK
- else if ($object=='addresslist' && function_exists('rcmail_contacts_list'))
- return rcmail_contacts_list($attrib);
-
- else if ($object=='addressframe' && function_exists('rcmail_contact_frame'))
- return rcmail_contact_frame($attrib);
-
- else if ($object=='recordscountdisplay' && function_exists('rcmail_rowcount_display'))
- return rcmail_rowcount_display($attrib);
-
- else if ($object=='contactdetails' && function_exists('rcmail_contact_details'))
- return rcmail_contact_details($attrib);
-
- else if ($object=='contacteditform' && function_exists('rcmail_contact_editform'))
- return rcmail_contact_editform($attrib);
-
-
- // USER SETTINGS
- else if ($object=='userprefs' && function_exists('rcmail_user_prefs_form'))
- return rcmail_user_prefs_form($attrib);
-
- else if ($object=='itentitieslist' && function_exists('rcmail_identities_list'))
- return rcmail_identities_list($attrib);
-
- else if ($object=='identityframe' && function_exists('rcmail_identity_frame'))
- return rcmail_identity_frame($attrib);
-
- else if ($object=='identityform' && function_exists('rcube_identity_form'))
- return rcube_identity_form($attrib);
-
- else if ($object=='foldersubscription' && function_exists('rcube_subscription_form'))
- return rcube_subscription_form($attrib);
-
- else if ($object=='createfolder' && function_exists('rcube_create_folder_form'))
- return rcube_create_folder_form($attrib);
-
+
+ // execute object handler function
+ else if ($object_handlers[$object] && function_exists($object_handlers[$object]))
+ return call_user_func($object_handlers[$object], $attrib);
else if ($object=='pagetitle')
{
@@ -878,7 +953,7 @@ function rcube_button($attrib)
// generate image tag
if ($attrib['type']=='image')
{
- $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'alt'));
+ $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'align', 'alt'));
$img_tag = sprintf('<img src="%%s"%s />', $attrib_str);
$btn_content = sprintf($img_tag, $skin_path.$attrib['image']);
if ($attrib['label'])
@@ -1161,4 +1236,39 @@ EOF;
}
+
+function rcmail_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)',
+ 'X-EUC-JP' => 'EUC-JP (Japanese)',
+ 'EUC-KR' => 'EUC-KR (Korean)',
+ 'BIG5' => 'BIG5 (Chinese)',
+ 'GB2312' => 'GB2312 (Chinese)',
+ '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'] : $GLOBALS['CHARSET'];
+ return $select->show($set);
+ }
+
+
?> \ No newline at end of file
diff --git a/program/include/rcube_db.inc b/program/include/rcube_db.inc
index f13ab55c0..acb13ce37 100755
--- a/program/include/rcube_db.inc
+++ b/program/include/rcube_db.inc
@@ -23,299 +23,332 @@
require_once('DB.php');
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 $a_query_results = array('dummy');
- var $last_res_id = 0;
-
- // PHP 5 constructor
- function __construct($db_dsnw,$db_dsnr='')
+ {
+ 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 $a_query_results = array('dummy');
+ var $last_res_id = 0;
+
+
+ // PHP 5 constructor
+ function __construct($db_dsnw,$db_dsnr='')
{
- if ($db_dsnr=='') $db_dsnr=$db_dsnw;
+ if ($db_dsnr=='')
+ $db_dsnr=$db_dsnw;
- $this->db_dsnw = $db_dsnw;
- $this->db_dsnr = $db_dsnr;
+ $this->db_dsnw = $db_dsnw;
+ $this->db_dsnr = $db_dsnr;
- $dsn_array = DB::parseDSN($db_dsnw);
- $this->db_provider = $dsn_array['phptype'];
+ $dsn_array = DB::parseDSN($db_dsnw);
+ $this->db_provider = $dsn_array['phptype'];
}
- // PHP 4 compatibility
- function rcube_db($db_dsnw,$db_dsnr='')
+
+ // PHP 4 compatibility
+ function rcube_db($db_dsnw,$db_dsnr='')
{
- $this->__construct($db_dsnw,$db_dsnr);
+ $this->__construct($db_dsnw,$db_dsnr);
}
- // Connect to specific database
- function dsn_connect($dsn)
+
+ // Connect to specific database
+ function dsn_connect($dsn)
{
- // Use persistent connections if available
- $dbh = DB::connect($dsn, array('persistent' => $true));
+ // Use persistent connections if available
+ $dbh = DB::connect($dsn, array('persistent' => TRUE));
- if (DB::isError($dbh))
- raise_error(array('code' => 500,
+ if (DB::isError($dbh))
+ raise_error(array('code' => 500,
'type' => 'db',
'line' => __LINE__,
'file' => __FILE__,
'message' => $dbh->getMessage()), TRUE, 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);
- }
+ 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;
+ return $dbh;
}
- // Connect to appropiate databse
- 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;
+ // Connect to appropiate databse
+ 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;
- }
+ // 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;
+ if ($mode=='r')
+ $dsn = $this->db_dsnr;
+ else
+ $dsn = $this->db_dsnw;
- $this->db_handle = $this->dsn_connect($dsn);
- $this->db_connected = true;
+ $this->db_handle = $this->dsn_connect($dsn);
+ $this->db_connected = true;
}
- // Query database
-
- function query()
+
+ // Query database
+ function query()
{
- $params = func_get_args();
- $query = array_shift($params);
-
- return $this->_query($query, 0, 0, $params);
+ $params = func_get_args();
+ $query = array_shift($params);
+
+ return $this->_query($query, 0, 0, $params);
}
-
- function limitquery()
+
+
+ // Query with limits
+ function limitquery()
{
- $params = func_get_args();
- $query = array_shift($params);
- $offset = array_shift($params);
- $numrows = array_shift($params);
+ $params = func_get_args();
+ $query = array_shift($params);
+ $offset = array_shift($params);
+ $numrows = array_shift($params);
- return $this->_query($query, $offset, $numrows, $params);
+ return $this->_query($query, $offset, $numrows, $params);
}
-
- function _query($query, $offset, $numrows, $params)
+
+
+ function _query($query, $offset, $numrows, $params)
{
- // Read or write ?
- if (strtolower(trim(substr($query,0,6)))=='select')
- $mode='r';
- else
- $mode='w';
+ // Read or write ?
+ if (strtolower(trim(substr($query,0,6)))=='select')
+ $mode='r';
+ else
+ $mode='w';
- $this->db_connect($mode);
+ $this->db_connect($mode);
- if ($this->db_provider == 'sqlite')
- $query = $this->_sqlite_prepare_query($query);
-
- if ($numrows || $offset)
- {
- $result = $this->db_handle->limitQuery($query,$offset,$numrows,$params);
- }
- else
- $result = $this->db_handle->query($query, $params);
+ if ($this->db_provider == 'sqlite')
+ $this->_sqlite_prepare();
- if (DB::isError($result))
- {
- raise_error(array('code' => 500,
- 'type' => 'db',
- 'line' => __LINE__,
- 'file' => __FILE__,
- 'message' => $result->getMessage().'; QUERY: '.$query), TRUE, FALSE);
- return false;
- }
-
- return $this->_add_result($result, $query);
+ 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);
}
-
- function num_rows($res_id=NULL)
+
+
+ function num_rows($res_id=NULL)
{
- if (!$this->db_handle)
- return FALSE;
+ if (!$this->db_handle)
+ return FALSE;
- $result = $this->_get_result($res_id);
-
- if ($result)
- return $result->numRows();
- else
- return FALSE;
+ if ($result = $this->_get_result($res_id))
+ return $result->numRows();
+ else
+ return FALSE;
}
- function affected_rows($res_id=NULL)
+
+ function affected_rows($res_id=NULL)
{
- if (!$this->db_handle)
- return FALSE;
-
- return $this->db_handle->affectedRows();
+ if (!$this->db_handle)
+ return FALSE;
+
+ return $this->db_handle->affectedRows();
}
- function insert_id($sequence = '')
+
+ function insert_id($sequence = '')
{
- if (!$this->db_handle || $this->db_mode=='r')
- return FALSE;
-
- switch($this->db_provider)
- {
- case 'pgsql':
- // PostgreSQL uses sequences
- $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, TRUE);
- }
- return $result;
+ if (!$this->db_handle || $this->db_mode=='r')
+ return FALSE;
+
+ switch($this->db_provider)
+ {
+ case 'pgsql':
+ // PostgreSQL uses sequences
+ $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 'mysql': // This is unfortuneate
- return mysql_insert_id($this->db_handle->connection);
+ case 'mysql': // This is unfortuneate
+ return mysql_insert_id($this->db_handle->connection);
- case 'mysqli':
- return mysqli_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);
+ case 'sqlite':
+ return sqlite_last_insert_rowid($this->db_handle->connection);
- default:
- die("portability issue with this database, please have the developer fix");
- }
+ default:
+ die("portability issue with this database, please have the developer fix");
+ }
}
- function fetch_assoc($res_id=NULL)
+ function fetch_assoc($res_id=NULL)
{
- $result = $this->_get_result($res_id);
-
- if (DB::isError($result))
- {
- raise_error( array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_link->getMessage()), TRUE, FALSE);
- return FALSE;
- }
+ $result = $this->_get_result($res_id);
+
+ if (DB::isError($result))
+ {
+ raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => $this->db_link->getMessage()), TRUE, FALSE);
+ return FALSE;
+ }
- return $result->fetchRow(DB_FETCHMODE_ASSOC);
+ return $result->fetchRow(DB_FETCHMODE_ASSOC);
}
- function quote($input, $type=null)
+ function quote($input, $type=null)
{
- if (!$this->db_handle)
- $this->db_connect('r');
+ if (!$this->db_handle)
+ $this->db_connect('r');
- return $this->db_handle->quote($input);
+ return $this->db_handle->quote($input);
}
- function quoteIdentifier($str)
+ function quoteIdentifier($str)
{
- if (!$this->db_handle)
- $this->db_connect('r');
+ if (!$this->db_handle)
+ $this->db_connect('r');
- return $this->db_handle->quoteIdentifier($str);
- }
-
- function quote_identifier($str)
- {
- return $this->quoteIdentifier($str);
+ return $this->db_handle->quoteIdentifier($str);
}
-
- function unixtimestamp($field)
- {
- switch($this->db_provider)
- {
- case 'pgsql':
- return "EXTRACT (EPOCH FROM $field)";
- break;
- default:
- return "UNIX_TIMESTAMP($field)";
- }
- }
-
- function _add_result($res, $query)
+
+ function quote_identifier($str)
+ {
+ return $this->quoteIdentifier($str);
+ }
+
+
+ function unixtimestamp($field)
{
- // 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*/', ' ', $query), 0, 1024)), 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;
- }
+ switch($this->db_provider)
+ {
+ case 'pgsql':
+ return "EXTRACT (EPOCH FROM $field)";
+ break;
+
+ default:
+ return "UNIX_TIMESTAMP($field)";
+ }
}
- function _get_result($res_id)
+ function fromunixtime($timestamp)
{
- if ($res_id==NULL)
- $res_id = $this->last_res_id;
+ switch($this->db_provider)
+ {
+ case 'mysqli':
+ case 'mysql':
+ case 'sqlite':
+ return "FROM_UNIXTIME($timestamp)";
+
+ default:
+ return date("'Y-m-d H:i:s'", $timestamp);
+ }
+ }
+
+
+ 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, 1024)), 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;
+ }
+ }
+
+
+ function _get_result($res_id)
+ {
+ 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;
+ 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
- function _sqlite_create_database($dbh, $fileName)
+ // create a sqlite database from a file
+ function _sqlite_create_database($dbh, $fileName)
{
- if (empty($fileName) || !is_string($fileName))
- return ;
-
- $data = '';
- if ($fd = fopen($fileName, 'r'))
- {
- $data = fread($fd, filesize($fileName));
- fclose($fd);
- }
-
- if (strlen($data))
- sqlite_exec($dbh->connection, $data);
+ if (empty($fileName) || !is_string($fileName))
+ return ;
+
+ $data = '';
+ if ($fd = fopen($fileName, 'r'))
+ {
+ $data = fread($fd, filesize($fileName));
+ fclose($fd);
+ }
+
+ if (strlen($data))
+ sqlite_exec($dbh->connection, $data);
}
- // transform a query so that it is sqlite2 compliant
- function _sqlite_prepare_query($query)
+ function _sqlite_prepare()
{
- if (!is_string($query))
- return ($query);
-
- $search = array('/NOW\(\)/i', '/`/');
- $replace = array("datetime('now')", '"');
- $query = preg_replace($search, $replace, $query);
+ include_once('include/rcube_sqlite.inc');
- return ($query);
+ // 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");
}
-
-}
+
+/*
+ // transform a query so that it is sqlite2 compliant
+ function _sqlite_prepare_query($query)
+ {
+ if (!is_string($query))
+ return ($query);
+
+
+ $search = array('/NOW\(\)/i', '/`/');
+ $replace = array("datetime('now')", '"');
+ $query = preg_replace($search, $replace, $query);
+
+ return ($query);
+ }
+*/
+ } // end class rcube_db
?> \ No newline at end of file
diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc
index 2237b38f3..ed7c3edcd 100644
--- a/program/include/rcube_imap.inc
+++ b/program/include/rcube_imap.inc
@@ -28,6 +28,7 @@ require_once('lib/utf7.inc');
class rcube_imap
{
+ var $db;
var $conn;
var $root_ns = '';
var $root_dir = '';
@@ -38,21 +39,23 @@ class rcube_imap
var $caching_enabled = FALSE;
var $default_folders = array('inbox', 'drafts', 'sent', 'junk', 'trash');
var $cache = array();
+ var $cache_keys = array();
var $cache_changes = array();
var $uid_id_map = array();
var $msg_headers = array();
+ var $capabilities = array();
// PHP 5 constructor
- function __construct()
+ function __construct($db_conn)
{
-
+ $this->db = $db_conn;
}
// PHP 4 compatibility
- function rcube_imap()
+ function rcube_imap($db_conn)
{
- $this->__construct();
+ $this->__construct($db_conn);
}
@@ -95,6 +98,7 @@ class rcube_imap
// get account namespace
if ($this->conn)
{
+ $this->_parse_capability($this->conn->capability);
iil_C_NameSpace($this->conn);
if (!empty($this->conn->delimiter))
@@ -185,6 +189,13 @@ class rcube_imap
}
+ function get_capability($cap)
+ {
+ $cap = strtoupper($cap);
+ return $this->capabilities[$cap];
+ }
+
+
function get_hierarchy_delimiter()
{
if ($this->conn && empty($this->delimiter))
@@ -298,200 +309,131 @@ class rcube_imap
// private method for listing message header
- // by DrSlump <drslump@drslump.biz>
- function __list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
+ function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
{
- $a_out = array();
- $cached_count = 0;
-
if (!strlen($mailbox))
- return $a_out;
+ return array();
+
+ $max = $this->_messagecount($mailbox);
+ $start_msg = ($this->list_page-1) * $this->page_size;
+
+ if ($page=='all')
+ {
+ $begin = 0;
+ $end = $max;
+ }
+ else if ($sort_order=='DESC')
+ {
+ $begin = $max - $this->page_size - $start_msg;
+ $end = $max - $start_msg;
+ }
+ else
+ {
+ $begin = $start_msg;
+ $end = $start_msg + $this->page_size;
+ }
- $mbox_count = $this->_messagecount($mailbox /*, 'ALL', TRUE*/);
+ if ($begin < 0) $begin = 0;
+ if ($end < 0) $end = $max;
+ if ($end > $max) $end = $max;
- $revalidate = false;
- if ($mbox_count)
+//console("fetch headers $start_msg to ".($start_msg+$this->page_size)." (msg $begin to $end)");
+
+ $headers_sorted = FALSE;
+ $cache_key = $mailbox.'.msg';
+ $cache_status = $this->check_cache_status($mailbox, $cache_key);
+
+//console("Cache status = $cache_status");
+
+ // cache is OK, we can get all messages from local cache
+ if ($cache_status>0)
+ {
+ $a_msg_headers = $this->get_message_cache($cache_key, $start_msg, $start_msg+$this->page_size, $sort_field, $sort_order);
+ $headers_sorted = TRUE;
+ }
+ else
{
- // get cached headers
- $a_out = $this->get_cache($mailbox.'.msg');
- $a_out = is_array($a_out) ? $a_out : array(); // make sure we get an array
-
- $cached_count = count($a_out);
- $a_new = array();
- $revalidate = true; // revalidate by default
-
- // if the cache count is greater then there have been changes for sure
- if ($cached_count <= $mbox_count)
+ // retrieve headers from IMAP
+ if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $sort_field)))
{
- $from = $cached_count?$cached_count:1;
-
- //get new headers (at least one is returned)
- $a_temp = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $mbox_count);
- $duplicated = $cached_count?true:false;
-
- foreach ($a_temp as $hdr)
+//console("$mailbox: ".count($msg_index));
+
+ $msgs = $msg_index[$begin];
+ for ($i=$begin; $i < $end; $i++)
{
- //skip the first one if duplicated
- if ($duplicated)
- {
- //check for changes using the UID
- $lastCacheHdr = end($a_out);
- if ($hdr->uid === $lastCacheHdr->uid)
- $revalidate = false;
-
- $duplicated = false;
- continue;
- }
-
- //skip deleted ones
- if (! $hdr->deleted)
- $a_new[ $hdr->uid ] = $hdr;
+ if ($sort_order == 'DESC')
+ $msgs = $msg_index[$i].','.$msgs;
+ else
+ $msgs = $msgs.','.$msg_index[$i];
}
- }
- //revalidate cache if needed
- $to = $mbox_count - count($a_new);
- if ($revalidate && $to !== 0) //we'll need to reindex the array so we have to make a copy
+ $sorted = TRUE;
+ }
+ else
{
- $a_dirty = $a_out;
- $a_out = array();
- $a_buffers = array();
+ $msgs = sprintf("%d:%d", $begin+1, $end);
+ $sorted = FALSE;
+ }
- //fetch chunks of 20 headers
- $step = 20;
- $found = false;
-
- //fetch headers in blocks starting from new to old
- do {
- $from = $to-$step;
- if ($from < 1) $from = 1;
- //store the block in a temporal buffer
- $a_buffers[$from] = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $to);
+ // cache is dirty, sync it
+ if ($this->caching_enabled && $cache_status==-1)
+ {
+ $this->sync_header_index($mailbox);
+ return $this->_list_headers($mailbox, $page, $sort_field, $sort_order);
+ }
+
- //compare the fetched headers with the ones in the cache
- $idx = 0;
- foreach ($a_buffers[$from] as $k=>$hdr)
+ // cache is incomplete
+ $cache_index = $this->get_message_cache_index($cache_key);
+
+ // fetch reuested headers from server
+ $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, $msgs);
+ $a_msg_headers = array();
+
+
+ if (!empty($a_header_index))
+ {
+ foreach ($a_header_index as $i => $headers)
+ {
+ if ($headers->deleted)
{
- //if it's different the comparison ends
- if (!isset($a_dirty[$hdr->uid]) || $a_dirty[$hdr->uid]->id !== $hdr->id)
- break;
+ // delete from cache
+ if ($cache_index[$headers->id] && $cache_index[$headers->id] == $headers->uid)
+ $this->remove_message_cache($cache_key, $headers->id);
- //if we arrive here then we know that the older messages in cache are ok
- $found = $hdr->id;
- $idx++;
+ continue;
}
- //remove from the buffer the headers which are already cached
- if ($found)
- $a_buffers[$from] = array_splice($a_buffers[$from], 0, $idx );
-
- $to = $from-1;
- }
- while ($found===false && $from > 1);
+ // add message to cache
+ if ($this->caching_enabled && $cache_index[$headers->id] != $headers->uid)
+ $this->add_message_cache($cache_key, $headers->id, $headers);
- //just keep the headers we are certain that didn't change in the cache
- if ($found !== false)
- {
- foreach ($a_dirty as $hdr)
- {
- if ($hdr->id > $found) break;
- $a_out[$hdr->uid] = $hdr;
- }
- }
-
- //we builded the block buffers from new to older, we process them in reverse order
- ksort($a_buffers, SORT_NUMERIC);
- foreach ($a_buffers as $a_buff)
- {
- foreach ($a_buff as $hdr)
- {
- if (! $hdr->deleted)
- $a_out[$hdr->uid] = $hdr;
- }
+ $a_msg_headers[$headers->uid] = $headers;
}
}
-
- //array_merge() would reindex the keys, so we use this 'hack'
- $a_out += $a_new;
- }
-
- //write headers list to cache if needed
- if ($revalidate || count($a_out)!=$cached_count) {
- $this->update_cache($mailbox.'.msg', $a_out);
- }
-
- //sort headers by a specific col
- $a_out = iil_SortHeaders( $a_out, $sort_field, $sort_order );
-
- // return complete list of messages
- if (strtolower($page)=='all')
- return $a_out;
- $start_msg = ($this->list_page-1) * $this->page_size;
- return array_slice($a_out, $start_msg, $this->page_size);
- }
+ // delete cached messages with a higher index than $max
+ $this->clear_message_cache($cache_key, $max);
- // original function; replaced 2005/10/18
- // private method for listing message header
- function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
- {
- $max = $this->_messagecount($mailbox);
-
- if (!strlen($mailbox))
- return array();
-
- // get cached headers
- $a_msg_headers = $this->get_cache($mailbox.'.msg');
-
- // retrieve headers from IMAP
- if (!is_array($a_msg_headers) || sizeof($a_msg_headers) != $max)
- {
- $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, "1:$max");
- $a_msg_headers = array();
-
- if (!empty($a_header_index))
- foreach ($a_header_index as $i => $headers)
- if (!$headers->deleted)
- $a_msg_headers[$headers->uid] = $headers;
- }
- else
- $headers_cached = TRUE;
-
- if (!is_array($a_msg_headers))
- return array();
-
- // sort headers by a specific col
- $a_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order);
- $headers_count = count($a_headers);
-
- // free memory
- unset($a_msg_headers);
-
- // write headers list to cache
- if (!$headers_cached)
- $this->update_cache($mailbox.'.msg', $a_headers);
+ // kick child process to sync cache
- // update message count cache
- $a_mailbox_cache = $this->get_cache('messagecount');
- if (isset($a_mailbox_cache[$mailbox]['ALL']) && $a_mailbox_cache[$mailbox]['ALL'] != $headers_count)
- {
- $a_mailbox_cache[$mailbox]['ALL'] = (int)$headers_count;
- $this->update_cache('messagecount', $a_mailbox_cache);
}
- if (empty($a_headers))
+
+ // return empty array if no messages found
+ if (!is_array($a_msg_headers) || empty($a_msg_headers))
return array();
-
- // return complete list of messages
- if (strtolower($page)=='all')
- return $a_headers;
- $start_msg = ($this->list_page-1) * $this->page_size;
- return array_slice($a_headers, $start_msg, $this->page_size);
+
+ // if not already sorted
+ if (!$headers_sorted)
+ $a_msg_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order);
+
+ return array_values($a_msg_headers);
}
-
+
// return sorted array of message UIDs
function message_index($mbox='', $sort_field='date', $sort_order='DESC')
@@ -510,9 +452,54 @@ class rcube_imap
}
- function sync_header_index($mbox=NULL)
+ function sync_header_index($mailbox)
{
-
+ $cache_key = $mailbox.'.msg';
+ $cache_index = $this->get_message_cache_index($cache_key);
+ $msg_count = $this->_messagecount($mailbox);
+
+ // fetch complete message index
+ $a_message_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:$msg_count", 'UID');
+
+ foreach ($a_message_index as $id => $uid)
+ {
+ // message in cache at correct position
+ if ($cache_index[$id] == $uid)
+ {
+// console("$id / $uid: OK");
+ unset($cache_index[$id]);
+ continue;
+ }
+
+ // message in cache but in wrong position
+ if (in_array((string)$uid, $cache_index, TRUE))
+ {
+// console("$id / $uid: Moved");
+ unset($cache_index[$id]);
+ }
+
+ // other message at this position
+ if (isset($cache_index[$id]))
+ {
+// console("$id / $uid: Delete");
+ $this->remove_message_cache($cache_key, $id);
+ unset($cache_index[$id]);
+ }
+
+
+// console("$id / $uid: Add");
+
+ // fetch complete headers and add to cache
+ $headers = iil_C_FetchHeader($this->conn, $mailbox, $id);
+ $this->add_message_cache($cache_key, $headers->id, $headers);
+ }
+
+ // those ids that are still in cache_index have been deleted
+ if (!empty($cache_index))
+ {
+ foreach ($cache_index as $id => $uid)
+ $this->remove_message_cache($cache_key, $id);
+ }
}
@@ -527,22 +514,19 @@ class rcube_imap
function get_headers($uid, $mbox=NULL)
{
$mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
-
+
// get cached headers
- $a_msg_headers = $this->get_cache($mailbox.'.msg');
-
- // return cached header
- if ($a_msg_headers[$uid])
- return $a_msg_headers[$uid];
+ if ($headers = $this->get_cached_message($mailbox.'.msg', $uid))
+ return $headers;
$msg_id = $this->_uid2id($uid);
- $header = iil_C_FetchHeader($this->conn, $mailbox, $msg_id);
+ $headers = iil_C_FetchHeader($this->conn, $mailbox, $msg_id);
// write headers cache
- $a_msg_headers[$uid] = $header;
- $this->update_cache($mailbox.'.msg', $a_msg_headers);
+ if ($headers)
+ $this->add_message_cache($mailbox.'.msg', $msg_id, $headers);
- return $header;
+ return $headers;
}
@@ -595,19 +579,20 @@ class rcube_imap
// reload message headers if cached
$cache_key = $this->mailbox.'.msg';
- if ($this->caching_enabled && $result && ($a_cached_headers = $this->get_cache($cache_key)))
+ if ($this->caching_enabled)
{
- // close and re-open connection
- $this->reconnect();
-
- foreach ($uids as $uid)
+ foreach ($msg_ids as $id)
{
- if (isset($a_cached_headers[$uid]))
+ if ($cached_headers = $this->get_cached_message($cache_key, $id))
{
- unset($this->cache[$cache_key][$uid]);
- $this->get_headers($uid);
+ $this->remove_message_cache($cache_key, $id);
+ //$this->get_headers($uid);
}
}
+
+ // close and re-open connection
+ // this prevents connection problems with Courier
+ $this->reconnect();
}
// set nr of messages that were flaged
@@ -633,7 +618,7 @@ class rcube_imap
// make shure mailbox exists
if (in_array($mailbox, $this->_list_mailboxes()))
$saved = iil_C_Append($this->conn, $mailbox, $message);
-
+
if ($saved)
{
// increase messagecount of the target mailbox
@@ -672,20 +657,24 @@ class rcube_imap
// really deleted from the source mailbox
if ($moved)
{
- $this->expunge($from_mbox, FALSE);
- $this->clear_cache($to_mbox.'.msg');
+ $this->_expunge($from_mbox, FALSE);
$this->_clear_messagecount($from_mbox);
$this->_clear_messagecount($to_mbox);
}
// update cached message headers
$cache_key = $from_mbox.'.msg';
- if ($moved && ($a_cached_headers = $this->get_cache($cache_key)))
+ if ($moved && ($a_cache_index = $this->get_message_cache_index($cache_key)))
{
+ $start_index = 100000;
foreach ($a_uids as $uid)
- unset($a_cached_headers[$uid]);
+ {
+ $index = array_search($uid, $a_cache_index);
+ $start_index = min($index, $start_index);
+ }
- $this->update_cache($cache_key, $a_cached_headers);
+ // clear cache from the lowest index on
+ $this->clear_message_cache($cache_key, $start_index);
}
return $moved;
@@ -716,17 +705,23 @@ class rcube_imap
// really deleted from the mailbox
if ($deleted)
{
- $this->expunge($mailbox, FALSE);
+ $this->_expunge($mailbox, FALSE);
$this->_clear_messagecount($mailbox);
}
// remove deleted messages from cache
- if ($deleted && ($a_cached_headers = $this->get_cache($mailbox.'.msg')))
+ $cache_key = $mailbox.'.msg';
+ if ($deleted && ($a_cache_index = $this->get_message_cache_index($cache_key)))
{
+ $start_index = 100000;
foreach ($a_uids as $uid)
- unset($a_cached_headers[$uid]);
+ {
+ $index = array_search($uid, $a_cache_index);
+ $start_index = min($index, $start_index);
+ }
- $this->update_cache($mailbox.'.msg', $a_cached_headers);
+ // clear cache from the lowest index on
+ $this->clear_message_cache($cache_key, $start_index);
}
return $deleted;
@@ -740,7 +735,10 @@ class rcube_imap
$msg_count = $this->_messagecount($mailbox, 'ALL');
if ($msg_count>0)
+ {
+ $this->clear_message_cache($mailbox.'.msg');
return iil_C_ClearFolder($this->conn, $mailbox);
+ }
else
return 0;
}
@@ -750,12 +748,18 @@ class rcube_imap
function expunge($mbox='', $clear_cache=TRUE)
{
$mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
-
+ return $this->_expunge($mailbox, $clear_cache);
+ }
+
+
+ // send IMAP expunge command and clear cache
+ function _expunge($mailbox, $clear_cache=TRUE)
+ {
$result = iil_C_Expunge($this->conn, $mailbox);
if ($result>=0 && $clear_cache)
{
- $this->clear_cache($mailbox.'.msg');
+ //$this->clear_message_cache($mailbox.'.msg');
$this->_clear_messagecount($mailbox);
}
@@ -763,7 +767,6 @@ class rcube_imap
}
-
/* --------------------------------
* folder managment
* --------------------------------*/
@@ -824,13 +827,18 @@ class rcube_imap
function create_mailbox($name, $subscribe=FALSE)
{
$result = FALSE;
+
+ // replace backslashes
+ $name = preg_replace('/[\\\]+/', '-', $name);
+
$name_enc = UTF7EncodeString($name);
+
+ // reduce mailbox name to 100 chars
+ $name_enc = substr($name_enc, 0, 100);
+
$abs_name = $this->_mod_mailbox($name_enc);
$a_mailbox_cache = $this->get_cache('mailboxes');
-
- //if (strlen($this->root_ns))
- // $abs_name = $this->root_ns.$abs_name;
-
+
if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache)))
$result = iil_C_CreateFolder($this->conn, $abs_name);
@@ -875,37 +883,41 @@ class rcube_imap
// clear mailboxlist cache
if ($deleted)
+ {
+ $this->clear_message_cache($mailbox.'.msg');
$this->clear_cache('mailboxes');
+ }
- return $updated;
+ return $deleted;
}
/* --------------------------------
- * internal caching functions
+ * internal caching methods
* --------------------------------*/
function set_caching($set)
{
- if ($set && function_exists('rcube_read_cache'))
+ if ($set && is_object($this->db))
$this->caching_enabled = TRUE;
else
$this->caching_enabled = FALSE;
}
+
function get_cache($key)
{
// read cache
if (!isset($this->cache[$key]) && $this->caching_enabled)
{
- $cache_data = rcube_read_cache('IMAP.'.$key);
+ $cache_data = $this->_read_cache_record('IMAP.'.$key);
$this->cache[$key] = strlen($cache_data) ? unserialize($cache_data) : FALSE;
}
- return $this->cache[$key];
+ return $this->cache[$key];
}
@@ -924,7 +936,7 @@ class rcube_imap
foreach ($this->cache as $key => $data)
{
if ($this->cache_changes[$key])
- rcube_write_cache('IMAP.'.$key, serialize($data));
+ $this->_write_cache_record('IMAP.'.$key, serialize($data));
}
}
}
@@ -935,7 +947,7 @@ class rcube_imap
if ($key===NULL)
{
foreach ($this->cache as $key => $data)
- rcube_clear_cache('IMAP.'.$key);
+ $this->_clear_cache_record('IMAP.'.$key);
$this->cache = array();
$this->cache_changed = FALSE;
@@ -943,7 +955,7 @@ class rcube_imap
}
else
{
- rcube_clear_cache('IMAP.'.$key);
+ $this->_clear_cache_record('IMAP.'.$key);
$this->cache_changes[$key] = FALSE;
unset($this->cache[$key]);
}
@@ -951,8 +963,276 @@ class rcube_imap
+ function _read_cache_record($key)
+ {
+ $cache_data = FALSE;
+
+ if ($this->db)
+ {
+ // get cached data from DB
+ $sql_result = $this->db->query(
+ "SELECT cache_id, data
+ FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $key);
+
+ if ($sql_arr = $this->db->fetch_assoc($sql_result))
+ {
+ $cache_data = $sql_arr['data'];
+ $this->cache_keys[$key] = $sql_arr['cache_id'];
+ }
+ }
+
+ return $cache_data;
+ }
+
+
+ function _write_cache_record($key, $data)
+ {
+ if (!$this->db)
+ return FALSE;
+
+ // check if we already have a cache entry for this key
+ if (!isset($this->cache_keys[$key]))
+ {
+ $sql_result = $this->db->query(
+ "SELECT cache_id
+ FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $key);
+
+ if ($sql_arr = $this->db->fetch_assoc($sql_result))
+ $this->cache_keys[$key] = $sql_arr['cache_id'];
+ else
+ $this->cache_keys[$key] = FALSE;
+ }
+
+ // update existing cache record
+ if ($this->cache_keys[$key])
+ {
+ $this->db->query(
+ "UPDATE ".get_table_name('cache')."
+ SET created=now(),
+ data=?
+ WHERE user_id=?
+ AND cache_key=?",
+ $data,
+ $_SESSION['user_id'],
+ $key);
+ }
+ // add new cache record
+ else
+ {
+ $this->db->query(
+ "INSERT INTO ".get_table_name('cache')."
+ (created, user_id, cache_key, data)
+ VALUES (now(), ?, ?, ?)",
+ $_SESSION['user_id'],
+ $key,
+ $data);
+ }
+ }
+
+
+ function _clear_cache_record($key)
+ {
+ $this->db->query(
+ "DELETE FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $key);
+ }
+
+
+
+ /* --------------------------------
+ * message caching methods
+ * --------------------------------*/
+
+
+ // checks if the cache is up-to-date
+ // return: -3 = off, -2 = incomplete, -1 = dirty
+ function check_cache_status($mailbox, $cache_key)
+ {
+ if (!$this->caching_enabled)
+ return -3;
+
+ $cache_index = $this->get_message_cache_index($cache_key, TRUE);
+ $msg_count = $this->_messagecount($mailbox);
+ $cache_count = count($cache_index);
+
+ // console("Cache check: $msg_count !== ".count($cache_index));
+
+ if ($cache_count==$msg_count)
+ {
+ // get highest index
+ $header = iil_C_FetchHeader($this->conn, $mailbox, "$msg_count");
+ $cache_uid = array_pop($cache_index);
+
+ // uids of highes message matches -> cache seems OK
+ if ($cache_uid == $header->uid)
+ return 1;
+
+ // cache is dirty
+ return -1;
+ }
+ // if cache count differs less that 10% report as dirty
+ else if (abs($msg_count - $cache_count) < $msg_count/10)
+ return -1;
+ else
+ return -2;
+ }
+
+
+
+ function get_message_cache($key, $from, $to, $sort_field, $sort_order)
+ {
+ $cache_key = "$key:$from:$to:$sort_field:$sort_order";
+ $db_header_fields = array('idx', 'uid', 'subject', 'from', 'to', 'cc', 'date', 'size');
+
+ if (!in_array($sort_field, $db_header_fields))
+ $sort_field = 'idx';
+
+ if ($this->caching_enabled && !isset($this->cache[$cache_key]))
+ {
+ $this->cache[$cache_key] = array();
+ $sql_result = $this->db->limitquery(
+ "SELECT idx, uid, headers
+ FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ ORDER BY ".$this->db->quoteIdentifier($sort_field)." ".
+ strtoupper($sort_order),
+ $from,
+ $to-$from,
+ $_SESSION['user_id'],
+ $key);
+
+ while ($sql_arr = $this->db->fetch_assoc($sql_result))
+ {
+ $uid = $sql_arr['uid'];
+ $this->cache[$cache_key][$uid] = unserialize($sql_arr['headers']);
+ }
+ }
+
+ return $this->cache[$cache_key];
+ }
+
+
+ function get_cached_message($key, $uid, $body=FALSE)
+ {
+ if (!$this->caching_enabled)
+ return FALSE;
+
+ $internal_key = '__single_msg';
+ if ($this->caching_enabled && (!isset($this->cache[$internal_key][$uid]) || $body))
+ {
+ $sql_select = "idx, uid, headers";
+ if ($body)
+ $sql_select .= ", body";
+
+ $sql_result = $this->db->query(
+ "SELECT $sql_select
+ FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ AND uid=?",
+ $_SESSION['user_id'],
+ $key,
+ $uid);
+
+ if ($sql_arr = $this->db->fetch_assoc($sql_result))
+ {
+ $headers = unserialize($sql_arr['headers']);
+ if (is_object($headers) && !empty($sql_arr['body']))
+ $headers->body = $sql_arr['body'];
+
+ $this->cache[$internal_key][$uid] = $headers;
+ }
+ }
+
+ return $this->cache[$internal_key][$uid];
+ }
+
+
+ function get_message_cache_index($key, $force=FALSE)
+ {
+ static $sa_message_index = array();
+
+ if (!empty($sa_message_index[$key]) && !$force)
+ return $sa_message_index[$key];
+
+ $sa_message_index[$key] = array();
+ $sql_result = $this->db->query(
+ "SELECT idx, uid
+ FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ ORDER BY idx ASC",
+ $_SESSION['user_id'],
+ $key);
+
+ while ($sql_arr = $this->db->fetch_assoc($sql_result))
+ $sa_message_index[$key][$sql_arr['idx']] = $sql_arr['uid'];
+
+ return $sa_message_index[$key];
+ }
+
+
+ function add_message_cache($key, $index, $headers)
+ {
+ $this->db->query(
+ "INSERT INTO ".get_table_name('messages')."
+ (user_id, del, cache_key, idx, uid, subject, ".$this->db->quoteIdentifier('from').", ".$this->db->quoteIdentifier('to').", cc, date, size, headers)
+ VALUES (?, 0, ?, ?, ?, ?, ?, ?, ?, ".$this->db->fromunixtime($headers->timestamp).", ?, ?)",
+ $_SESSION['user_id'],
+ $key,
+ $index,
+ $headers->uid,
+ $this->decode_header($headers->subject, TRUE),
+ $this->decode_header($headers->from, TRUE),
+ $this->decode_header($headers->to, TRUE),
+ $this->decode_header($headers->cc, TRUE),
+ $headers->size,
+ serialize($headers));
+ }
+
+
+ function remove_message_cache($key, $index)
+ {
+ $this->db->query(
+ "DELETE FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ AND idx=?",
+ $_SESSION['user_id'],
+ $key,
+ $index);
+ }
+
+
+ function clear_message_cache($key, $start_index=1)
+ {
+ $this->db->query(
+ "DELETE FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ AND idx>=?",
+ $_SESSION['user_id'],
+ $key,
+ $start_index);
+ }
+
+
+
+
/* --------------------------------
- * encoding/decoding functions
+ * encoding/decoding methods
* --------------------------------*/
@@ -986,9 +1266,15 @@ class rcube_imap
}
- function decode_header($input)
+ function decode_header($input, $remove_quotes=FALSE)
{
- return $this->decode_mime_string($input);
+ $str = $this->decode_mime_string($input);
+ if ($str{0}=='"' && $remove_quotes)
+ {
+ $str = str_replace('"', '', $str);
+ }
+
+ return $str;
}
@@ -1094,6 +1380,7 @@ class rcube_imap
}
+
/* --------------------------------
* private methods
* --------------------------------*/
@@ -1149,6 +1436,33 @@ class rcube_imap
}
+ // parse string or array of server capabilities and put them in internal array
+ function _parse_capability($caps)
+ {
+ if (!is_array($caps))
+ $cap_arr = explode(' ', $caps);
+ else
+ $cap_arr = $caps;
+
+ foreach ($cap_arr as $cap)
+ {
+ if ($cap=='CAPABILITY')
+ continue;
+
+ if (strpos($cap, '=')>0)
+ {
+ list($key, $value) = explode('=', $cap);
+ if (!is_array($this->capabilities[$key]))
+ $this->capabilities[$key] = array();
+
+ $this->capabilities[$key][] = $value;
+ }
+ else
+ $this->capabilities[$cap] = TRUE;
+ }
+ }
+
+
// subscribe/unsubscribe a list of mailboxes and update local cache
function _change_subscription($a_mboxes, $mode)
{
diff --git a/program/include/rcube_mdb2.inc b/program/include/rcube_mdb2.inc
index 35973ad5d..54a40e796 100755
--- a/program/include/rcube_mdb2.inc
+++ b/program/include/rcube_mdb2.inc
@@ -238,6 +238,22 @@ class rcube_db
}
+ function format_date($timestamp)
+ {
+ switch($this->db_provider)
+ {
+ case 'mysqli':
+ case 'mysql':
+ return "FROM_UNIXTIME($timestamp)";
+ break;
+ case 'sqlite':
+ return "datetime('$timestamp')";
+ break;
+ default:
+ return date("Y-m-d H:i:s", $timestamp);
+ }
+ }
+
function _add_result($res, $query)
{
// sql error occured
diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc
index 400e345c0..75db7603f 100644
--- a/program/include/rcube_shared.inc
+++ b/program/include/rcube_shared.inc
@@ -1185,99 +1185,6 @@ function send_future_expire_header()
}
-// replace specials characters to a specific encoding type
-function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
- {
- global $OUTPUT_TYPE, $CHARSET;
- static $html_encode_arr, $js_rep_table, $rtf_rep_table, $xml_rep_table;
-
- if (!$enctype)
- $enctype = $GLOBALS['OUTPUT_TYPE'];
-
- // convert nbsps back to normal spaces if not html
- if ($enctype!='html')
- $str = str_replace(chr(160), ' ', $str);
-
-
- // encode for plaintext
- if ($enctype=='text')
- return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
-
- // encode for HTML output
- if ($enctype=='html')
- {
- if (!$html_encode_arr)
- {
- if ($CHARSET=='ISO-8859-1')
- {
- $html_encode_arr = get_html_translation_table(HTML_ENTITIES);
- $html_encode_arr[chr(128)] = '&euro;';
- }
- else
- $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
-
- unset($html_encode_arr['?']);
- unset($html_encode_arr['&']);
- }
-
- $ltpos = strpos($str, '<');
- $encode_arr = $html_encode_arr;
-
- // don't replace quotes and html tags
- if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false)
- {
- unset($encode_arr['"']);
- unset($encode_arr['<']);
- unset($encode_arr['>']);
- }
- else if ($mode=='remove')
- $str = strip_tags($str);
-
- $out = strtr($str, $encode_arr);
-
- return $newlines ? nl2br($out) : $out;
- }
-
-
- if ($enctype=='url')
- return rawurlencode($str);
-
-
- // if the replace tables for RTF, XML and JS are not yet defined
- if (!$js_rep_table)
- {
- $js_rep_table = $rtf_rep_table = $xml_rep_table = array();
-
- for ($c=160; $c<256; $c++) // can be increased to support more charsets
- {
- $hex = dechex($c);
- $rtf_rep_table[Chr($c)] = "\\'$hex";
- $xml_rep_table[Chr($c)] = "&#$c;";
-
- if ($CHARSET=='ISO-8859-1')
- $js_rep_table[Chr($c)] = sprintf("\u%s%s", str_repeat('0', 4-strlen($hex)), $hex);
- }
-
- $js_rep_table['"'] = sprintf("\u%s%s", str_repeat('0', 4-strlen(dechex(34))), dechex(34));
- $xml_rep_table['"'] = '&quot;';
- }
-
- // encode for RTF
- if ($enctype=='xml')
- return strtr($str, $xml_rep_table);
-
- // encode for javascript use
- if ($enctype=='js')
- return preg_replace(array("/\r\n/", '/"/', "/([^\\\])'/"), array('\n', '\"', "$1\'"), strtr($str, $js_rep_table));
-
- // encode for RTF
- if ($enctype=='rtf')
- return preg_replace("/\r\n/", "\par ", strtr($str, $rtf_rep_table));
-
- // no encoding given -> return original string
- return $str;
- }
-
function decode_specialchars($input, $charset='')
{
@@ -1462,7 +1369,21 @@ function abbrevate_string($str, $maxlength, $place_holder='...')
return $str;
}
-
+
+
+// delete all files within a folder
+function clear_directory($dir_path)
+ {
+ $dir = @opendir($dir_path);
+ if(!$dir) return FALSE;
+
+ while ($file = readdir($dir))
+ if (strlen($file)>2)
+ unlink("$dir_path/$file");
+
+ closedir($dir);
+ return TRUE;
+ }
?> \ No newline at end of file
diff --git a/program/include/rcube_sqlite.inc b/program/include/rcube_sqlite.inc
new file mode 100644
index 000000000..78c671d38
--- /dev/null
+++ b/program/include/rcube_sqlite.inc
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_sqlite.inc |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2005, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Provide callback functions for sqlite that will emulate |
+ | sone MySQL functions |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+
+function rcube_sqlite_from_unixtime($timestamp)
+ {
+ $timestamp = trim($timestamp);
+ if (!preg_match("/^[0-9]+$/is", $timestamp))
+ $ret = strtotime($timestamp);
+ else
+ $ret = $timestamp;
+
+ $ret = date("Y-m-d H:i:s", $ret);
+ rcube_sqlite_debug("FROM_UNIXTIME ($timestamp) = $ret");
+ return $ret;
+ }
+
+
+function rcube_sqlite_unix_timestamp($timestamp="")
+ {
+ $timestamp = trim($timestamp);
+ if (!$timestamp)
+ $ret = time();
+ else if (!preg_match("/^[0-9]+$/is", $timestamp))
+ $ret = strtotime($timestamp);
+ else
+ $ret = $timestamp;
+
+ rcube_sqlite_debug("UNIX_TIMESTAMP ($timestamp) = $ret");
+ return $ret;
+ }
+
+
+function rcube_sqlite_now()
+ {
+ rcube_sqlite_debug("NOW() = ".date("Y-m-d H:i:s"));
+ return date("Y-m-d H:i:s");
+ }
+
+
+function rcube_sqlite_md5($str)
+ {
+ return md5($str);
+ }
+
+
+function rcube_sqlite_debug($str)
+ {
+ //console($str);
+ }
+
+?> \ No newline at end of file
diff --git a/program/include/session.inc b/program/include/session.inc
index 54ed798fc..f10a2b37e 100644
--- a/program/include/session.inc
+++ b/program/include/session.inc
@@ -45,7 +45,7 @@ function sess_read($key)
if ($sql_arr = $DB->fetch_assoc($sql_result))
{
- $SESS_CHANGED = $sql_arr['changed'];
+ $SESS_CHANGED = mktime(); //$sql_arr['changed'];
if (strlen($sql_arr['vars']))
return $sql_arr['vars'];
@@ -59,7 +59,7 @@ function sess_read($key)
function sess_write($key, $vars)
{
global $DB;
-
+
$sql_result = $DB->query("SELECT 1
FROM ".get_table_name('session')."
WHERE sess_id=?",
@@ -83,6 +83,8 @@ function sess_write($key, $vars)
$key,
$vars,
$_SERVER['REMOTE_ADDR']);
+
+
}
return TRUE;
@@ -102,7 +104,9 @@ function sess_destroy($key)
$DB->query("DELETE FROM ".get_table_name('session')."
WHERE sess_id=?",
$key);
-
+
+ rcmail_clear_session_temp($key);
+
return TRUE;
}
@@ -115,7 +119,7 @@ function sess_gc($maxlifetime)
// get all expired sessions
$sql_result = $DB->query("SELECT sess_id
FROM ".get_table_name('session')."
- WHERE ".$DB->unixtimestamp('now()')."-".$DB->unixtimestamp('created')." > ?",
+ WHERE ".$DB->unixtimestamp('now()')."-".$DB->unixtimestamp('changed')." > ?",
$maxlifetime);
$a_exp_sessions = array();
@@ -134,6 +138,10 @@ function sess_gc($maxlifetime)
WHERE sess_id IN ('".join("','", $a_exp_sessions)."')");
}
+ // remove session specific temp dirs
+ foreach ($a_exp_sessions as $key)
+ rcmail_clear_session_temp($key);
+
return TRUE;
}