Optimized loading time; added periodic mail check; added EXPUNGE command

release-0.6
thomascube 19 years ago
parent 977a295eb1
commit 15a9d1ce67

@ -1,6 +1,20 @@
CHANGELOG RoundCube Webmail
---------------------------
2006/01/04
----------
- Fixed bug when inserting signatures with !?&
- Chopping message headers before inserting into the message cache table (to avoid bugs in Postgres)
- Allow one-char domains in e-mail addresses
- Make product name in page title configurable
- Make username available as skin object
- Added session_write_close() in rcube_db class destructor to avoid problems in PHP 5.0.5
- Use move_uploaded_file() instead of copy() for a more secure handling of uploaded attachments
- Additional config parameter to show/hide deleted messages
- Added periodic request for checking new mails (Request #1307821)
- Added EXPUNGE command
- Optimized loading time for mail interface
2005/12/16
----------

@ -76,6 +76,7 @@ REQUIREMENTS
* The Apache Webserver
* .htaccess support allowing overrides for DirectoryIndex
* PHP Version 4.3.1 or greater
* PCRE (perl compatible regular expression) installed with PHP
* php.ini options:
- error_reporting E_ALL & ~E_NOTICE (or lower)
- file_uploads on (for attachment upload features)

@ -91,7 +91,7 @@ CREATE TABLE `users` (
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`last_login` datetime NOT NULL default '0000-00-00 00:00:00',
`language` varchar(5) NOT NULL default 'en',
`preferences` text NOT NULL,
`preferences` text NOT NULL default '',
PRIMARY KEY (`user_id`)
) TYPE=MyISAM;

@ -2,8 +2,8 @@
-- Version 0.1-20051007
ALTER TABLE session ADD ip VARCHAR(15) NOT NULL AFTER changed;
ALTER TABLE users ADD alias VARCHAR(128) NOT NULL AFTER mail_host;
ALTER TABLE `session` ADD `ip` VARCHAR(15) NOT NULL AFTER changed;
ALTER TABLE `users` ADD `alias` VARCHAR(128) NOT NULL AFTER mail_host;

@ -68,7 +68,7 @@ CREATE SEQUENCE message_ids
--
CREATE TABLE users (
user_id integer DEFAULT nextval('user_ids'::text) NOT NULL,
user_id integer DEFAULT nextval('user_ids'::text) PRIMARY KEY,
username character varying(128) DEFAULT ''::character varying NOT NULL,
mail_host character varying(128) DEFAULT ''::character varying NOT NULL,
alias character varying(128) DEFAULT ''::character varying NOT NULL,
@ -86,7 +86,7 @@ CREATE TABLE users (
--
CREATE TABLE "session" (
sess_id character varying(40) DEFAULT ''::character varying NOT NULL,
sess_id character varying(40) DEFAULT ''::character varying PRIMARY KEY,
created timestamp with time zone DEFAULT now() NOT NULL,
changed timestamp with time zone DEFAULT now() NOT NULL,
ip character varying(16) NOT NULL,
@ -101,8 +101,8 @@ CREATE TABLE "session" (
--
CREATE TABLE identities (
identity_id integer DEFAULT nextval('identity_ids'::text) NOT NULL,
user_id integer DEFAULT 0 NOT NULL,
identity_id integer DEFAULT nextval('identity_ids'::text) PRIMARY KEY,
user_id integer NOT NULL REFERENCES users (user_id),
del integer DEFAULT 0 NOT NULL,
standard integer DEFAULT 0 NOT NULL,
name character varying(128) NOT NULL,
@ -120,8 +120,8 @@ CREATE TABLE identities (
--
CREATE TABLE contacts (
contact_id integer DEFAULT nextval('contact_ids'::text) NOT NULL,
user_id integer DEFAULT 0 NOT NULL,
contact_id integer DEFAULT nextval('contact_ids'::text) PRIMARY KEY,
user_id integer NOT NULL REFERENCES users (user_id),
changed timestamp with time zone DEFAULT now() NOT NULL,
del integer DEFAULT 0 NOT NULL,
name character varying(128) DEFAULT ''::character varying NOT NULL,
@ -139,9 +139,9 @@ CREATE TABLE contacts (
--
CREATE TABLE "cache" (
cache_id integer DEFAULT nextval('cache_ids'::text) NOT NULL,
user_id integer DEFAULT 0 NOT NULL,
session_id character varying(40),
cache_id integer DEFAULT nextval('cache_ids'::text) PRIMARY KEY,
user_id integer NOT NULL REFERENCES users (user_id),
session_id character varying(40) REFERENCES "session" (session_id),
cache_key character varying(128) DEFAULT ''::character varying NOT NULL,
created timestamp with time zone DEFAULT now() NOT NULL,
data text NOT NULL
@ -155,8 +155,8 @@ CREATE TABLE "cache" (
--
CREATE TABLE "messages" (
message_id integer DEFAULT nextval('message_ids'::text) NOT NULL,
user_id integer DEFAULT 0 NOT NULL,
message_id integer DEFAULT nextval('message_ids'::text) PRIMARY KEY,
user_id integer NOT NULL REFERENCES users (user_id),
del integer DEFAULT 0 NOT NULL,
cache_key character varying(128) DEFAULT ''::character varying NOT NULL,
idx integer DEFAULT 0 NOT NULL,
@ -171,55 +171,3 @@ CREATE TABLE "messages" (
body text
);
--
-- Add primary keys
--
ALTER TABLE ONLY "cache"
ADD CONSTRAINT cache_pkey PRIMARY KEY (cache_id);
ALTER TABLE ONLY "contacts"
ADD CONSTRAINT contacts_pkey PRIMARY KEY (contact_id);
ALTER TABLE ONLY identities
ADD CONSTRAINT identities_pkey PRIMARY KEY (identity_id);
ALTER TABLE ONLY "session"
ADD CONSTRAINT session_pkey PRIMARY KEY (sess_id);
ALTER TABLE ONLY "users"
ADD CONSTRAINT users_pkey PRIMARY KEY (user_id);
ALTER TABLE ONLY "messages"
ADD CONSTRAINT messages_pkey PRIMARY KEY (message_id);
--
-- Reference keys
--
ALTER TABLE ONLY "cache"
ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
ALTER TABLE ONLY "cache"
ADD CONSTRAINT "$2" FOREIGN KEY (session_id) REFERENCES "session"(sess_id);
ALTER TABLE ONLY "contacts"
ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
ALTER TABLE ONLY "identities"
ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
ALTER TABLE ONLY "messages"
ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);

@ -19,6 +19,7 @@ from versions 0.1-alpha and 0.1-20050811
$rcmail_config['smtp_port'] = 25;
$rcmail_config['default_port'] = 143;
$rcmail_config['session_lifetime'] = 20;
$rcmail_config['skip_deleted'] = FALSE;
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
@ -41,6 +42,7 @@ from version 0.1-20050820
$rcmail_config['smtp_port'] = 25;
$rcmail_config['default_port'] = 143;
$rcmail_config['session_lifetime'] = 20;
$rcmail_config['skip_deleted'] = FALSE;
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
@ -61,6 +63,7 @@ from version 0.1-20051007
- add these lines to /config/main.inc.php
$rcmail_config['smtp_auth_type'] = ''; // if you need to specify an auth method for SMTP
$rcmail_config['session_lifetime'] = 20; // to specify the session lifetime in minutes
$rcmail_config['skip_deleted'] = FALSE;
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
@ -81,6 +84,7 @@ from version 0.1-20051021
- replace all files in folder /skins/default/
- run all commands in SQL/*.update.sql or re-initalize database with *.initial.sql
- add these lines to /config/main.inc.php
$rcmail_config['skip_deleted'] = FALSE;
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
@ -91,4 +95,5 @@ from version 0.1-20051021
$rcmail_config['db_sequence_identity_ids'] = 'identity_ids';
$rcmail_config['db_sequence_contact_ids'] = 'contact_ids';
$rcmail_config['db_sequence_cache_ids'] = 'cache_ids';
$rcmail_config['db_sequence_message_ids'] = 'message_ids';
$rcmail_config['db_sequence_message_ids'] = 'message_ids';

@ -97,6 +97,9 @@ $rcmail_config['date_long'] = 'd.m.Y H:i';
// add this user-agent to message headers when sending
$rcmail_config['useragent'] = 'RoundCube Webmail/0.1b';
// use this name to compose page titles
$rcmail_config['product_name'] = 'RoundCube Webmail';
// only list folders within this path
$rcmail_config['imap_root'] = '';

@ -3,7 +3,7 @@
/*
+-----------------------------------------------------------------------+
| RoundCube Webmail IMAP Client |
| Version 0.1-20051214 |
| Version 0.1-20060104 |
| |
| Copyright (C) 2005, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
@ -41,6 +41,9 @@
*/
define('RCMAIL_VERSION', '0.1-20060104');
// define global vars
$INSTALL_PATH = dirname($_SERVER['SCRIPT_FILENAME']);
$OUTPUT_TYPE = 'html';
@ -240,6 +243,15 @@ if ($_task=='mail')
if ($_action=='addcontact')
include('program/steps/mail/addcontact.inc');
if ($_action=='expunge')
include('program/steps/mail/folders.inc');
if ($_action=='check-recent')
include('program/steps/mail/check_recent.inc');
if ($_action=='getunread')
include('program/steps/mail/getunread.inc');
if ($_action=='list' && $_GET['_remote'])
include('program/steps/mail/list.inc');

@ -146,6 +146,9 @@ function rcmail_imap_init($connect=FALSE)
global $CONFIG, $DB, $IMAP;
$IMAP = new rcube_imap($DB);
$IMAP->debug_level = $CONFIG['debug_level'];
$IMAP->skip_deleted = $CONFIG['skip_deleted'];
// connect with stored session data
if ($connect)
@ -591,14 +594,25 @@ function decrypt_passwd($cypher)
// send correct response on a remote request
function rcube_remote_response($js_code)
function rcube_remote_response($js_code, $flush=FALSE)
{
send_nocacheing_headers();
header('Content-Type: application/x-javascript');
static $s_header_sent = FALSE;
if (!$s_header_sent)
{
$s_header_sent = TRUE;
send_nocacheing_headers();
header('Content-Type: application/x-javascript');
print '/** remote response ['.date('d/M/Y h:i:s O')."] **/\n";
}
print '/** remote response ['.date('d/M/Y h:i:s O')."] **/\n";
// send response code
print $js_code;
exit;
if ($flush) // flush the output buffer
flush();
else // terminate script
exit;
}
@ -879,8 +893,13 @@ function rcube_xml_command($command, $str_attrib, $a_attrib=NULL)
$object = strtolower($attrib['name']);
$object_handlers = array(
// GENERAL
'loginform' => 'rcmail_login_form',
'username' => 'rcmail_current_username',
// MAIL
'mailboxlist' => 'rcmail_mailbox_list',
'message' => 'rcmail_message_container',
'messages' => 'rcmail_message_list',
'messagecountdisplay' => 'rcmail_messagecount_display',
'messageheaders' => 'rcmail_message_headers',
@ -916,32 +935,28 @@ function rcube_xml_command($command, $str_attrib, $a_attrib=NULL)
'composebody' => 'rcmail_compose_body'
);
if ($object=='loginform')
return rcmail_login_form($attrib);
else if ($object=='message')
return rcmail_message_container($attrib);
// execute object handler function
else if ($object_handlers[$object] && function_exists($object_handlers[$object]))
if ($object_handlers[$object] && function_exists($object_handlers[$object]))
return call_user_func($object_handlers[$object], $attrib);
else if ($object=='pagetitle')
{
$task = $GLOBALS['_task'];
$title = !empty($CONFIG['product_name']) ? $CONFIG['product_name'].' :: ' : '';
if ($task=='mail' && isset($GLOBALS['MESSAGE']['subject']))
return rep_specialchars_output("RoundCube|Mail :: ".$GLOBALS['MESSAGE']['subject']);
$title .= $GLOBALS['MESSAGE']['subject'];
else if (isset($GLOBALS['PAGE_TITLE']))
return rep_specialchars_output("RoundCube|Mail :: ".$GLOBALS['PAGE_TITLE']);
$title .= $GLOBALS['PAGE_TITLE'];
else if ($task=='mail' && ($mbox_name = $IMAP->get_mailbox_name()))
return "RoundCube|Mail :: ".rep_specialchars_output(UTF7DecodeString($mbox_name), 'html', 'all');
$title .= UTF7DecodeString($mbox_name);
else
return "RoundCube|Mail :: $task";
$title .= $task;
return rep_specialchars_output($title, 'html', 'all');
}
else if ($object=='about')
return '';
break;
}
@ -1266,6 +1281,38 @@ function rcmail_message_container($attrib)
}
// return the IMAP username of the current session
function rcmail_current_username($attrib)
{
global $DB;
static $s_username;
// alread fetched
if (!empty($s_username))
return $s_username;
// get e-mail address form default identity
$sql_result = $DB->query("SELECT email AS mailto
FROM ".get_table_name('identities')."
WHERE user_id=?
AND standard=1
AND del<>1",
$_SESSION['user_id']);
if ($DB->num_rows($sql_result))
{
$sql_arr = $DB->fetch_assoc($sql_result);
$s_username = $sql_arr['mailto'];
}
else if (strstr($_SESSION['username'], '@'))
$s_username = $_SESSION['username'];
else
$s_username = $_SESSION['username'].'@'.$_SESSION['imap_host'];
return $s_username;
}
// return code for the webmail login form
function rcmail_login_form($attrib)
{
@ -1373,4 +1420,27 @@ function rcmail_charset_selector($attrib)
}
function rcube_timer()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function rcube_print_time($timer, $label='Timer')
{
static $print_count = 0;
$print_count++;
$now = rcube_timer();
$diff = $now-$timer;
if (empty($label))
$label = 'Timer '.$print_count;
console(sprintf("%s: %0.4f sec", $label, $diff));
}
?>

@ -20,8 +20,24 @@
*/
/**
* 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 RoundCube Webmail
* @author David Saez Padros <david@ols.es>
* @author Thomas Bruederli <roundcube@gmail.com>
* @version 1.14
* @link http://pear.php.net/package/DB
*/
class rcube_db
{
var $db_dsnw; // DSN for write operations
@ -34,8 +50,13 @@ class rcube_db
var $last_res_id = 0;
// PHP 5 constructor
function __construct($db_dsnw,$db_dsnr='')
/**
* Object constructor
*
* @param string DSN for read/write operations
* @param string Optional DSN for read only operations
*/
function __construct($db_dsnw, $db_dsnr='')
{
if ($db_dsnr=='')
$db_dsnr=$db_dsnw;
@ -48,25 +69,44 @@ class rcube_db
}
// PHP 4 compatibility
/**
* PHP 4 object constructor
*
* @see rcube_db::__construct
*/
function rcube_db($db_dsnw,$db_dsnr='')
{
$this->__construct($db_dsnw,$db_dsnr);
}
// Connect to specific database
/**
* Object destructor
*/
function __destruct()
{
// before closing the database connection, write session data
session_write_close();
}
/**
* 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' => TRUE));
if (DB::isError($dbh))
raise_error(array('code' => 500,
'type' => 'db',
'line' => __LINE__,
'file' => __FILE__,
{
raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
'message' => $dbh->getMessage()), TRUE, FALSE);
}
else if ($this->db_provider=='sqlite')
{
@ -79,8 +119,14 @@ class rcube_db
}
// Connect to appropiate databse
function db_connect ($mode)
/**
* Connect to appropiate databse
* depending on the operation
*
* @param string Connection mode (r|w)
* @access public
*/
function db_connect($mode)
{
$this->db_mode = $mode;
@ -99,7 +145,7 @@ class rcube_db
if ($this->db_mode==$mode)
return;
}
if ($mode=='r')
$dsn = $this->db_dsnr;
else
@ -110,7 +156,14 @@ class rcube_db
}
// Query database
/**
* 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();
@ -120,7 +173,16 @@ class rcube_db
}
// Query with limits
/**
* 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();
@ -132,6 +194,16 @@ class rcube_db
}
/**
* 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 ?
@ -155,6 +227,14 @@ class rcube_db
}
/**
* 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)
@ -167,7 +247,13 @@ class rcube_db
}
function affected_rows($res_id=NULL)
/**
* 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;
@ -176,6 +262,14 @@ class rcube_db
}
/**
* 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')
@ -185,10 +279,12 @@ class rcube_db
{
case 'pgsql':
// PostgreSQL uses sequences
$result =& $this->db_handle->getOne("SELECT CURRVAL('$sequence')");
$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;
@ -207,6 +303,14 @@ class rcube_db
}
/**
* 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);
@ -222,30 +326,66 @@ class rcube_db
}
function quote($input, $type=null)
/**
* 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');
return $this->db_handle->quote($input);
// 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)
{
if (!$this->db_handle)
$this->db_connect('r');
return $this->db_handle->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)
{
return $this->quoteIdentifier($str);
if (!$this->db_handle)
$this->db_connect('r');
return $this->db_handle->quoteIdentifier($str);
}
/**
* 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)
@ -260,6 +400,13 @@ class rcube_db
}
/**
* 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)
@ -275,13 +422,20 @@ class rcube_db
}
/**
* 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, 1024)), TRUE, FALSE);
'message' => $res->getMessage() . " Query: " . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)), TRUE, FALSE);
return FALSE;
}
else
@ -294,7 +448,15 @@ class rcube_db
}
function _get_result($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;
@ -306,16 +468,22 @@ class rcube_db
}
// create a sqlite database from a file
function _sqlite_create_database($dbh, $fileName)
/**
* 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($fileName) || !is_string($fileName))
return ;
if (empty($file_name) || !is_string($file_name))
return;
$data = '';
if ($fd = fopen($fileName, 'r'))
if ($fd = fopen($file_name, 'r'))
{
$data = fread($fd, filesize($fileName));
$data = fread($fd, filesize($file_name));
fclose($fd);
}
@ -323,6 +491,13 @@ class rcube_db
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');
@ -334,21 +509,7 @@ class rcube_db
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
?>

@ -21,11 +21,24 @@
*/
/**
* Obtain classes from the Iloha IMAP library
*/
require_once('lib/imap.inc');
require_once('lib/mime.inc');
require_once('lib/utf7.inc');
/**
* Interface class for accessing an IMAP server
*
* This is a wrapper that implements the Iloha IMAP Library (IIL)
*
* @package RoundCube Webmail
* @author Thomas Bruederli <roundcube@gmail.com>
* @version 1.22
* @link http://ilohamail.org
*/
class rcube_imap
{
var $db;
@ -46,33 +59,53 @@ class rcube_imap
var $uid_id_map = array();
var $msg_headers = array();
var $capabilities = array();
var $skip_deleted = FALSE;
var $debug_level = 1;
// PHP 5 constructor
/**
* Object constructor
*
* @param object Database connection
*/
function __construct($db_conn)
{
$this->db = $db_conn;
}
// PHP 4 compatibility
/**
* PHP 4 object constructor
*
* @see rcube_imap::__construct
*/
function rcube_imap($db_conn)
{
$this->__construct($db_conn);
}
/**
* Connect to an IMAP server
*
* @param string Host to connect
* @param string Username for IMAP account
* @param string Password for IMAP account
* @param number Port to connect to
* @param boolean Use SSL connection
* @return boolean TRUE on success, FALSE on failure
* @access public
*/
function connect($host, $user, $pass, $port=143, $use_ssl=FALSE)
{
global $ICL_SSL, $ICL_PORT, $CONFIG;
global $ICL_SSL, $ICL_PORT;
// check for Open-SSL support in PHP build
if ($use_ssl && in_array('openssl', get_loaded_extensions()))
$ICL_SSL = TRUE;
else if ($use_ssl)
{
raise_error(array('code' => 403,
'type' => 'imap',
'file' => __FILE__,
raise_error(array('code' => 403, 'type' => 'imap', 'file' => __FILE__,
'message' => 'Open SSL not available;'), TRUE, FALSE);
$port = 143;
}
@ -86,7 +119,7 @@ class rcube_imap
$this->ssl = $use_ssl;
// print trace mesages
if ($this->conn && ($CONFIG['debug_level'] & 8))
if ($this->conn && ($this->debug_level & 8))
console($this->conn->message);
// write error log
@ -116,6 +149,12 @@ class rcube_imap
}
/**
* Close IMAP connection
* Usually done on script shutdown
*
* @access public
*/
function close()
{
if ($this->conn)
@ -123,6 +162,12 @@ class rcube_imap
}
/**
* Close IMAP connection and re-connect
* This is used to avoid some strange socket errors when talking to Courier IMAP
*
* @access public
*/
function reconnect()
{
$this->close();
@ -130,6 +175,15 @@ class rcube_imap
}
/**
* Set a root folder for the IMAP connection.
*
* Only folders within this root folder will be displayed
* and all folder paths will be translated using this folder name
*
* @param string Root folder
* @access public
*/
function set_rootdir($root)
{
if (ereg('[\.\/]$', $root)) //(substr($root, -1, 1)==='/')
@ -142,6 +196,12 @@ class rcube_imap
}
/**
* This list of folders will be listed above all other folders
*
* @param array Indexed list of folder names
* @access public
*/
function set_default_mailboxes($arr)
{
if (is_array($arr))
@ -159,6 +219,14 @@ class rcube_imap
}
/**
* Set internal mailbox reference.
*
* All operations will be perfomed on this mailbox/folder
*
* @param string Mailbox/Folder name
* @access public
*/
function set_mailbox($mbox)
{
$mailbox = $this->_mod_mailbox($mbox);
@ -173,24 +241,49 @@ class rcube_imap
}
/**
* 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;
}
/**
* Returns the currently used mailbox name
*
* @return string Name of the mailbox/folder
* @access public
*/
function get_mailbox_name()
{
return $this->conn ? $this->_mod_mailbox($this->mailbox, 'out') : '';
}
/**
* Returns the IMAP server's capability
*
* @param string Capability name
* @return mixed Capability value or TRUE if supported, FALSE if not
* @access public
*/
function get_capability($cap)
{
$cap = strtoupper($cap);
@ -198,6 +291,12 @@ class rcube_imap
}
/**
* Returns the delimiter that is used by the IMAP server for folder separation
*
* @return string Delimiter string
* @access public
*/
function get_hierarchy_delimiter()
{
if ($this->conn && empty($this->delimiter))
@ -209,8 +308,17 @@ class rcube_imap
return $this->delimiter;
}
// public method for mailbox listing
// convert mailbox name with root dir first
/**
* Public method for mailbox listing.
*
* Converts mailbox name with root dir first
*
* @param string Optional root folder
* @param string Optional filter for mailbox listing
* @return array List of mailboxes/folders
* @access public
*/
function list_mailboxes($root='', $filter='*')
{
$a_out = array();
@ -229,7 +337,14 @@ class rcube_imap
return $a_out;
}
// private method for mailbox listing
/**
* Private method for mailbox listing
*
* @return array List of mailboxes/folders
* @access private
* @see rcube_imap::list_mailboxes
*/
function _list_mailboxes($root='', $filter='*')
{
$a_defaults = $a_out = array();
@ -261,7 +376,7 @@ class rcube_imap
}
// get message count for a specific mailbox; acceptes modes are: ALL, UNSEEN
// get message count for a specific mailbox; acceptes modes are: ALL, UNSEEN, RECENT
function messagecount($mbox='', $mode='ALL', $force=FALSE)
{
$mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
@ -274,7 +389,7 @@ class rcube_imap
$a_mailbox_cache = FALSE;
$mode = strtoupper($mode);
if (!$mailbox)
if (empty($mailbox))
$mailbox = $this->mailbox;
$a_mailbox_cache = $this->get_cache('messagecount');
@ -282,22 +397,37 @@ class rcube_imap
// return cached value
if (!$force && is_array($a_mailbox_cache[$mailbox]) && isset($a_mailbox_cache[$mailbox][$mode]))
return $a_mailbox_cache[$mailbox][$mode];
$search_str = "ALL UNDELETED";
// get message count and store in cache
if ($mode == 'UNSEEN')
$search_str .= " UNSEEN";
// RECENT count is fetched abit different
if ($mode == 'RECENT')
$count = iil_C_CheckForRecent($this->conn, $mailbox);
// get message count using SEARCH
// not very performant but more precise (using UNDELETED)
$count = 0;
$index = $this->_search_index($mailbox, $search_str);
if (is_array($index))
// use SEARCH for message counting
else if ($this->skip_deleted)
{
$str = implode(",", $index);
if (!empty($str))
$count = count($index);
$search_str = "ALL UNDELETED";
// get message count and store in cache
if ($mode == 'UNSEEN')
$search_str .= " UNSEEN";
// get message count using SEARCH
// not very performant but more precise (using UNDELETED)
$count = 0;
$index = $this->_search_index($mailbox, $search_str);
if (is_array($index))
{
$str = implode(",", $index);
if (!empty($str))
$count = count($index);
}
}
else
{
if ($mode == 'UNSEEN')
$count = iil_C_CountUnseen($this->conn, $mailbox);
else
$count = iil_C_CountMessages($this->conn, $mailbox);
}
if (is_array($a_mailbox_cache[$mailbox]))
@ -348,7 +478,7 @@ class rcube_imap
else
{
$begin = $start_msg;
$end = $start_msg + $this->page_size;
$end = $start_msg + $this->page_size;
}
if ($begin < 0) $begin = 0;
@ -372,16 +502,16 @@ class rcube_imap
else
{
// retrieve headers from IMAP
if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field)))
if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')))
{
//console("$mailbox: ".count($msg_index));
//console("$mailbox: ".join(',', $msg_index));
$msgs = $msg_index[$begin];
for ($i=$begin; $i < $end; $i++)
for ($i=$begin+1; $i < $end; $i++)
{
if ($this->sort_order == 'DESC')
$msgs = $msg_index[$i].','.$msgs;
else
//if ($this->sort_order == 'DESC')
// $msgs = $msg_index[$i].','.$msgs;
//else
$msgs = $msgs.','.$msg_index[$i];
}
@ -401,44 +531,16 @@ class rcube_imap
return $this->_list_headers($mailbox, $page, $this->sort_field, $this->sort_order, TRUE);
}
// 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();
$deleted_count = 0;
if (!empty($a_header_index))
{
foreach ($a_header_index as $i => $headers)
{
if ($headers->deleted)
{
// delete from cache
if ($cache_index[$headers->id] && $cache_index[$headers->id] == $headers->uid)
$this->remove_message_cache($cache_key, $headers->id);
$deleted_count++;
continue;
}
// add message to cache
if ($this->caching_enabled && $cache_index[$headers->id] != $headers->uid)
$this->add_message_cache($cache_key, $headers->id, $headers);
$a_msg_headers[$headers->uid] = $headers;
}
}
$deleted_count = $this->_fetch_headers($mailbox, $msgs, $a_msg_headers, $cache_key);
// delete cached messages with a higher index than $max
$this->clear_message_cache($cache_key, $max);
// fetch more headers of there were any deleted messages
// ...
// kick child process to sync cache
// ...
@ -458,6 +560,53 @@ class rcube_imap
}
/**
* Fetches message headers
* Used for loop
*
* @param string Mailbox name
* @param string Message indey to fetch
* @param array Reference to message headers array
* @param array Array with cache index
* @return number Number of deleted messages
* @access private
*/
function _fetch_headers($mailbox, $msgs, &$a_msg_headers, $cache_key)
{
// 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);
$deleted_count = 0;
if (!empty($a_header_index))
{
foreach ($a_header_index as $i => $headers)
{
if ($headers->deleted && $this->skip_deleted)
{
// delete from cache
if ($cache_index[$headers->id] && $cache_index[$headers->id] == $headers->uid)
$this->remove_message_cache($cache_key, $headers->id);
$deleted_count++;
continue;
}
// add message to cache
if ($this->caching_enabled && $cache_index[$headers->id] != $headers->uid)
$this->add_message_cache($cache_key, $headers->id, $headers);
$a_msg_headers[$headers->uid] = $headers;
}
}
return $deleted_count;
}
// return sorted array of message UIDs
function message_index($mbox='', $sort_field=NULL, $sort_order=NULL)
{
@ -584,7 +733,7 @@ class rcube_imap
}
function get_headers($uid, $mbox=NULL)
function get_headers($id, $mbox=NULL, $is_uid=TRUE)
{
$mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
@ -592,7 +741,7 @@ class rcube_imap
if ($headers = $this->get_cached_message($mailbox.'.msg', $uid))
return $headers;
$msg_id = $this->_uid2id($uid);
$msg_id = $is_uid ? $this->_uid2id($id) : $id;
$headers = iil_C_FetchHeader($this->conn, $mailbox, $msg_id);
// write headers cache
@ -802,9 +951,9 @@ class rcube_imap
// clear all messages in a specific mailbox
function clear_mailbox($mbox)
function clear_mailbox($mbox=NULL)
{
$mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
$mailbox = !empty($mbox) ? $this->_mod_mailbox($mbox) : $this->mailbox;
$msg_count = $this->_messagecount($mailbox, 'ALL');
if ($msg_count>0)
@ -1270,10 +1419,10 @@ class rcube_imap
$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),
substr($this->decode_header($headers->subject, TRUE), 0, 128),
substr($this->decode_header($headers->from, TRUE), 0, 128),
substr($this->decode_header($headers->to, TRUE), 0, 128),
substr($this->decode_header($headers->cc, TRUE), 0, 128),
(int)$headers->size,
serialize($headers));
}

@ -6,11 +6,11 @@
| Copyright (C) 2005, RoundCube Dev, - Switzerland |
| Licensed under the GNU GPL |
| |
| Modified: 2005/12/16 (roundcube) |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
@ -137,7 +137,7 @@ function rcube_webmail()
this.enable_command('add-attachment', 'send-attachment', 'send', true);
if (this.env.messagecount)
this.enable_command('select-all', 'select-none', 'sort', true);
this.enable_command('select-all', 'select-none', 'sort', 'expunge', true);
this.set_page_buttons();
@ -151,6 +151,10 @@ function rcube_webmail()
// show printing dialog
if (this.env.action=='print')
window.print();
// get unread count for each mailbox
if (this.gui_objects.mailboxlist)
this.http_request('getunread', '');
break;
@ -219,9 +223,9 @@ function rcube_webmail()
if (this.pending_message)
this.display_message(this.pending_message[0], this.pending_message[1]);
// start interval for keep-alive siganl
// start interval for keep-alive/recent_check signal
if (this.kepp_alive_interval)
this.kepp_alive_int = setInterval(this.ref+'.send_keep_alive()', this.kepp_alive_interval);
this.kepp_alive_int = setInterval(this.ref+'.'+(this.task=='mail'?'check_for_recent()':'send_keep_alive()'), this.kepp_alive_interval);
};
@ -436,6 +440,15 @@ function rcube_webmail()
return false;
}
// check input before leaving compose step
if (this.task=='mail' && this.env.action=='compose' && (command=='list' || command=='mail' || command=='addressbook' || command=='settings'))
{
if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning')))
return false;
}
// process command
switch (command)
@ -460,13 +473,7 @@ function rcube_webmail()
// misc list commands
case 'list':
if (this.task=='mail')
{
// check input before leaving compose step
if (this.env.action=='compose' && this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning')))
break;
this.list_mailbox(props);
}
else if (this.task=='addressbook')
this.list_contacts();
break;
@ -512,6 +519,16 @@ function rcube_webmail()
this.list_page('prev');
break;
case 'expunge':
if (this.env.messagecount)
this.expunge_mailbox(this.env.mailbox);
break;
case 'clear-mailbox':
//if (this.env.messagecount)
//this.clear_mailbox(this.env.mailbox);
break;
// common commands used in multiple tasks
case 'show':
@ -1168,7 +1185,18 @@ function rcube_webmail()
// send remote request to load message list
this.list_mailbox_remote = function(mbox, page, add_url)
{
// clear message list
// clear message list first
this.clear_message_list();
// send request to server
var url = '_mbox='+escape(mbox)+(page ? '&_page='+page : '');
this.set_busy(true, 'loading');
this.http_request('list', url+add_url, true);
};
this.clear_message_list = function()
{
var table = this.gui_objects.messagelist;
var tbody = document.createElement('TBODY');
table.insertBefore(tbody, table.tBodies[0]);
@ -1176,11 +1204,26 @@ function rcube_webmail()
this.message_rows = new Array();
this.list_rows = this.message_rows;
};
this.expunge_mailbox = function(mbox)
{
var lock = false;
var add_url = '';
// lock interface if it's the active mailbox
if (mbox == this.env.mailbox)
{
lock = true;
this.set_busy(true, 'loading');
add_url = '&_reload=1';
}
// send request to server
var url = '_mbox='+escape(mbox)+(page ? '&_page='+page : '');
this.set_busy(true, 'loading');
this.http_request('list', url+add_url, true);
var url = '_mbox='+escape(mbox);
this.http_request('expunge', url+add_url, lock);
};
@ -2263,7 +2306,7 @@ function rcube_webmail()
// create a table row in the message list
this.add_message_row = function(uid, cols, flags, attachment)
this.add_message_row = function(uid, cols, flags, attachment, attop)
{
if (!this.gui_objects.messagelist || !this.gui_objects.messagelist.tBodies[0])
return false;
@ -2277,8 +2320,8 @@ function rcube_webmail()
var row = document.createElement('TR');
row.id = 'rcmrow'+uid;
row.className = 'message '+(even ? 'even' : 'odd')+(flags.unread ? ' unread' : '');
row.className = 'message '+(even ? 'even' : 'odd')+(flags.unread ? ' unread' : '')+(flags.deleted ? ' deleted' : '');
if (this.in_selection(uid))
row.className += ' selected';
@ -2304,7 +2347,11 @@ function rcube_webmail()
col.innerHTML = attachment && this.env.attachmenticon ? '<img src="'+this.env.attachmenticon+'" alt="" border="0" />' : '';
row.appendChild(col);
tbody.appendChild(row);
if (attop && tbody.rows.length)
tbody.insertBefore(row, tbody.firstChild);
else
tbody.appendChild(row);
this.init_message_row(row);
};
@ -2321,35 +2368,44 @@ function rcube_webmail()
// update the mailboxlist
this.set_unread_count = function(mbox, count)
this.set_unread_count = function(mbox, count, set_title)
{
if (!this.gui_objects.mailboxlist)
return false;
mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
var item, reg, text_obj;
for (var n=0; n<this.gui_objects.mailboxlist.childNodes.length; n++)
mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
item = document.getElementById('rcmbx'+mbox);
if (item && item.className && item.className.indexOf('mailbox '+mbox)>=0)
{
item = this.gui_objects.mailboxlist.childNodes[n];
// set new text
text_obj = item.firstChild;
reg = /\s+\([0-9]+\)$/i;
if (item.className && item.className.indexOf('mailbox '+mbox)>=0)
{
// set new text
text_obj = item.firstChild;
reg = /\s+\([0-9]+\)$/i;
if (count && text_obj.innerHTML.match(reg))
text_obj.innerHTML = text_obj.innerHTML.replace(reg, ' ('+count+')');
else if (count)
text_obj.innerHTML += ' ('+count+')';
else
text_obj.innerHTML = text_obj.innerHTML.replace(reg, '');
if (count && text_obj.innerHTML.match(reg))
text_obj.innerHTML = text_obj.innerHTML.replace(reg, ' ('+count+')');
else if (count)
text_obj.innerHTML += ' ('+count+')';
else
text_obj.innerHTML = text_obj.innerHTML.replace(reg, '');
// set the right classes
this.set_classname(item, 'unread', count>0 ? true : false);
break;
}
// set the right classes
this.set_classname(item, 'unread', count>0 ? true : false);
}
// set unread count to window title
if (set_title && document.title)
{
var doc_title = String(document.title);
reg = /^\([0-9]+\)\s+/i;
if (count && doc_title.match(reg))
document.title = doc_title.replace(reg, '('+count+') ');
else if (count)
document.title = '('+count+') '+doc_title;
else
document.title = doc_title.replace(reg, '');
}
};
@ -2527,9 +2583,10 @@ function rcube_webmail()
if (this.env.action=='show')
this.command('list');
break;
case 'list':
this.enable_command('select-all', 'select-none', this.env.messagecount ? true : false);
case 'expunge':
this.enable_command('select-all', 'select-none', 'expunge', this.env.messagecount ? true : false);
break;
}
@ -2556,7 +2613,14 @@ function rcube_webmail()
var d = new Date();
this.http_request('keep-alive', '_t='+d.getTime());
};
// send periodic request to check for recent messages
this.check_for_recent = function()
{
var d = new Date();
this.http_request('check-recent', '_t='+d.getTime());
};
/********************************************************/

@ -269,7 +269,7 @@ function rcube_check_email(input, inline)
{
if (input && window.RegExp)
{
var reg_str = '([a-z0-9][-a-z0-9\.\+_]*)\@([a-z0-9]([-a-z0-9][\.]?)*[a-z0-9]\.[a-z]{2,9})';
var reg_str = '([a-z0-9][-a-z0-9\.\+_]*)\@(([-a-z0-9][\.]?)*[a-z0-9]\.[a-z]{2,9})';
var reg1 = inline ? new RegExp(reg_str, 'i') : new RegExp('^'+reg_str+'$', 'i');
var reg2 = /[\._\-\@]{2}/;
return reg1.test(input) && !reg2.test(input) ? true : false;

@ -607,7 +607,7 @@ function iil_StrToTime($str){
return $time2;
}
function iil_C_Sort(&$conn, $mailbox, $field){
function iil_C_Sort(&$conn, $mailbox, $field, $add=''){
/* Do "SELECT" command */
if (!iil_C_Select($conn, $mailbox)) return false;
@ -618,7 +618,8 @@ function iil_C_Sort(&$conn, $mailbox, $field){
if (!$fields[$field]) return false;
$fp = $conn->fp;
$command = 's SORT ('.$field.') US-ASCII ALL UNDELETED'."\r\n";
$command = 's SORT ('.$field.') US-ASCII ALL '."$add\r\n";
//$command = 's SORT ('.$field.') US-ASCII ALL UNDELETED'."\r\n";
$line = $data = '';
if (!fputs($fp, $command)) return false;

@ -105,6 +105,9 @@ $labels['all'] = 'Alle';
$labels['none'] = 'Keine';
$labels['unread'] = 'Ungelesene';
$labels['compact'] = 'Packen';
// message compose // Nachrichten erstellen
$labels['compose'] = 'Neue Nachricht verfassen';
$labels['sendmessage'] = 'Nachricht jetzt senden';
@ -167,6 +170,7 @@ $labels['timezone'] = 'Zeitzone';
$labels['pagesize'] = 'Einträge pro Seite';
$labels['signature'] = 'Signatur';
$labels['folder'] = 'Ordner';
$labels['folders'] = 'Ordner';
$labels['foldername'] = 'Ordnername';
$labels['subscribed'] = 'Abonniert';

@ -105,6 +105,9 @@ $labels['all'] = 'All';
$labels['none'] = 'None';
$labels['unread'] = 'Unread';
$labels['compact'] = 'Compact';
// message compose
$labels['compose'] = 'Compose a message';
$labels['sendmessage'] = 'Send the message now';
@ -167,6 +170,7 @@ $labels['timezone'] = 'Time zone';
$labels['pagesize'] = 'Rows per page';
$labels['signature'] = 'Signature';
$labels['folder'] = 'Folder';
$labels['folders'] = 'Folders';
$labels['foldername'] = 'Folder name';
$labels['subscribed'] = 'Subscribed';

@ -0,0 +1,47 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/check_recent.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Check for recent messages |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
$REMOTE_REQUEST = TRUE;
$mbox = $IMAP->get_mailbox_name();
if ($recent_count = $IMAP->messagecount(NULL, 'RECENT'))
{
$count = $IMAP->messagecount();
$unread_count = $IMAP->messagecount(NULL, 'UNSEEN');
$commands = sprintf("this.set_unread_count('%s', %d, true);\n", addslashes($mbox), $unread_count);
$commands .= sprintf("this.set_env('messagecount', %d);\n", $count);
$commands .= sprintf("this.set_rowcount('%s');\n", rcmail_get_messagecount_text());
// add new message headers to list
$a_headers = array();
for ($i=$recent_count, $id=$count-$recent_count+1; $i>0; $i--, $id++)
$a_headers[] = $IMAP->get_headers($id, NULL, FALSE);
$commands .= rcmail_js_message_list($a_headers, TRUE);
}
if (strtoupper($mbox)!='INBOX' && $IMAP->messagecount('INBOX', 'RECENT'))
$commands = sprintf("this.set_unread_count('INBOX', %d);\n", $IMAP->messagecount('INBOX', 'UNSEEN'));
rcube_remote_response($commands);
?>

@ -0,0 +1,61 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/folders.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Implement folder operations line EXPUNGE and Clear |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
$REMOTE_REQUEST = TRUE;
$mbox = $IMAP->get_mailbox_name();
// send EXPUNGE command
if ($_action=='expunge')
{
$success = $IMAP->expunge();
// reload message list if current mailbox
if ($success && $_GET['_reload'])
{
rcube_remote_response('this.clear_message_list();', TRUE);
$_action = 'list';
return;
}
else
$commands = "// expunged: $success\n";
}
// clear mailbox
else if ($_action=='purge')
{
$success = $IMAP->clear_mailbox();
if ($success && $_GET['_reload'])
{
$commands = "this.set_env('messagecount', 0);\n";
$commands .= "this.set_env('pagecount', 0);\n";
$commands .= sprintf("this.set_rowcount('%s');\n", rcmail_get_messagecount_text());
$commands .= sprintf("this.set_unread_count('%s', 0);\n", addslashes($mbox));
}
else
$commands = "// purged: $success";
}
rcube_remote_response($commands);
?>

@ -69,6 +69,8 @@ function rcmail_mailbox_list($attrib)
static $s_added_script = FALSE;
static $a_mailboxes;
// $mboxlist_start = rcube_timer();
$type = $attrib['type'] ? $attrib['type'] : 'ul';
$add_attrib = $type=='select' ? array('style', 'class', 'id', 'name', 'onchange') :
array('style', 'class', 'id');
@ -100,7 +102,9 @@ function rcmail_mailbox_list($attrib)
$a_folders = $IMAP->list_mailboxes();
$delimiter = $IMAP->get_hierarchy_delimiter();
$a_mailboxes = array();
// rcube_print_time($mboxlist_start, 'list_mailboxes()');
foreach ($a_folders as $folder)
rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter);
}
@ -112,6 +116,8 @@ function rcmail_mailbox_list($attrib)
else
$out .= rcmail_render_folder_tree_html($a_mailboxes, $special_mailboxes, $mbox, $attrib['maxlength']);
// rcube_print_time($mboxlist_start, 'render_folder_tree()');
if ($type=='ul')
$OUTPUT->add_script(sprintf("%s.gui_object('mailboxlist', '%s');", $JS_OBJECT_NAME, $attrib['id']));
@ -181,7 +187,7 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$special, &$mbox, $maxlen
}
// add unread message count display
if ($unread_count = $IMAP->messagecount($folder['id'], 'UNSEEN', ($folder['id']==$mbox)))
if ($unread_count = $IMAP->messagecount($folder['id'], 'RECENT', ($folder['id']==$mbox)))
$foldername .= sprintf(' (%d)', $unread_count);
// make folder name safe for ids and class names
@ -397,7 +403,12 @@ function rcmail_message_list($attrib)
if ($attrib['attachmenticon'] && preg_match("/multipart\/m/i", $header->ctype))
$attach_icon = $attrib['attachmenticon'];
$out .= sprintf('<tr id="rcmrow%d" class="message'.($header->seen ? '' : ' unread').' '.$zebra_class.'">'."\n", $header->uid);
$out .= sprintf('<tr id="rcmrow%d" class="message%s%s %s">'."\n",
$header->uid,
$header->seen ? '' : ' unread',
$header->deleted ? ' deleted' : '',
$zebra_class);
$out .= sprintf("<td class=\"icon\">%s</td>\n", $message_icon ? sprintf($image_tag, $skin_path, $message_icon, '') : '');
// format each col
@ -495,12 +506,16 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE)
$a_msg_flags['unread'] = $header->seen ? 0 : 1;
$a_msg_flags['replied'] = $header->answered ? 1 : 0;
if ($header->deleted)
$a_msg_flags['deleted'] = 1;
$commands .= sprintf("this.add_message_row(%s, %s, %s, %b);\n",
$commands .= sprintf("this.add_message_row(%s, %s, %s, %b, %b);\n",
$header->uid,
array2js($a_msg_cols),
array2js($a_msg_flags),
preg_match("/multipart\/m/i", $header->ctype));
preg_match("/multipart\/m/i", $header->ctype),
$insert_top);
}
return $commands;
@ -1377,11 +1392,11 @@ function rcmail_compose_cleanup()
// remove attachment files from temp dir
if (is_array($_SESSION['compose']['attachments']))
foreach ($_SESSION['compose']['attachments'] as $attachment)
unlink($attachment['path']);
@unlink($attachment['path']);
// kill temp dir
if ($_SESSION['compose']['temp_dir'])
rmdir($_SESSION['compose']['temp_dir']);
@rmdir($_SESSION['compose']['temp_dir']);
unset($_SESSION['compose']);
}

@ -0,0 +1,36 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/getunread.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Check all mailboxes for unread messages and update GUI |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
$REMOTE_REQUEST = TRUE;
$a_folders = $IMAP->list_mailboxes();
if (!empty($a_folders))
{
foreach ($a_folders as $mbox)
{
$commands = sprintf("this.set_unread_count('%s', %d);\n", $mbox, $IMAP->messagecount($mbox, 'UNSEEN'));
rcube_remote_response($commands, TRUE);
}
}
exit;
?>

@ -224,14 +224,17 @@ else
{
// unset some headers because they will be added by the mail() function
$headers_php = $headers;
$headers_enc = $MAIL_MIME->headers($headers);
unset($headers_php['To'], $headers_php['Subject']);
// reset stored headers and overwrite
$MAIL_MIME->_headers = array();
$header_str = $MAIL_MIME->txtHeaders($headers_php);
if(ini_get('safe_mode'))
$sent = mail($mailto, $msg_subject, $msg_body, $header_str);
else
$sent = mail($mailto, $msg_subject, $msg_body, $header_str, "-f$from");
$sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str);
else
$sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str, "-f$from");
}

@ -39,7 +39,7 @@ $response = '';
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath)
{
$tmpfname = tempnam($temp_dir, 'rcmAttmnt');
if (copy($filepath, $tmpfname))
if (move_uploaded_file($filepath, $tmpfname))
{
$_SESSION['compose']['attachments'][] = array('name' => $_FILES['_attachments']['name'][$i],
'mimetype' => $_FILES['_attachments']['type'][$i],

@ -51,7 +51,10 @@
#listcontrols a,
#listcontrols a:active,
#listcontrols a:visited
#listcontrols a:visited,
#mailboxcontrols a,
#mailboxcontrols a:active,
#mailboxcontrols a:visited
{
color: #999999;
font-size: 11px;
@ -60,12 +63,16 @@
#listcontrols a.active,
#listcontrols a.active:active,
#listcontrols a.active:visited
#listcontrols a.active:visited,
#mailboxcontrols a.active,
#mailboxcontrols a.active:active,
#mailboxcontrols a.active:visited
{
color: #CC0000;
}
#listcontrols a.active:hover
#listcontrols a.active:hover,
#mailboxcontrols a.active:hover
{
text-decoration: underline;
}
@ -294,6 +301,17 @@
}
#mailboxcontrols
{
position: absolute;
left: 20px;
width: 160px;
bottom: 20px;
height: 16px;
overflow: hidden;
}
/** message list styles */
body.messagelist
@ -430,6 +448,12 @@ body.messagelist
color: #FFFFFF;
}
#messagelist tr.deleted td,
#messagelist tr.deleted td a
{
color: #CCCCCC;
}
/** message view styles */

@ -28,6 +28,11 @@
<div id="mailboxlist-header"><roundcube:label name="mailboxlist" /></div>
<div id="mailboxlist-container"><roundcube:object name="mailboxlist" id="mailboxlist" maxlength="16" /></div>
<div id="mailboxcontrols">
<roundcube:label name="folder" />:&nbsp;
<roundcube:button command="expunge" label="compact" classAct="active" />&nbsp;
</div>
<div id="mailcontframe">
<roundcube:object name="messages"

Loading…
Cancel
Save