Page MenuHomePhorge

No OneTemporary

Size
297 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/CHANGELOG b/CHANGELOG
index ed07dce16..1ed96f35e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,270 +1,279 @@
CHANGELOG RoundCube Webmail
---------------------------
+2006/06/30 (richs)
+----------
+- Fixed empty INBOX compatibility bug (Patch #1443200)
+- Temporarily fixed French "compact" localization (Patch #1483862)
+- Fixed "Select All" not working with Delete interface button (Bug #1332434)
+- Fixed messsage list column compatibility with Konqueror (Bug #1395711)
+- Fixed "unread count" in window title when count changed (Bug #1483812)
+- Fixed DB error when deleting from message table (Patch #1483835)
+
2006/06/29 (richs)
----------
- Added ability to remove attachments (Feature #1436721)
- Default folders are now auto-created on first login (Feature #1471594)
- Fixed compatibility with folder apostrophes (e.g.: Joe's Folder) (Bug #1429458)
- Corrected Italian localizations
- Tweaked rename-folder form to clear after a rename
2006/06/26 (richs)
----------
- Added button to immediately check for new messages
- New message checking now displays status "Checking for new messages..."
- New message checking now looks for unread messages in all mailboxes (Feature #1326401)
- Task buttons now respond to clicks by darkening (as in other applications)
- Fixed "Sender" column changing to "Recipient" for "Sent" and "Drafts" message lists
- Added ability to sort messages by "Size"
- Added ability to rename folders (Feature #1326396)
- Added 'protect_default_folders' option to main.inc.php to prevent renames/deletes/unsubscribes of default folders
- Corrected 5 typos of "INSTLL" to "INSTALL" in program/include/main.inc
2006/06/25
----------
- Changed behavior to include host-specific configuration (Bug #1483849)
- Assume ISO-8859-1 encoding of mail messages by default (Patch #1483839)
- Fixed spell checker to work with the new URL at google.com
- Some memory and security optimizations sendmail.inc
- Updated UGRADING description
2006/06/19
----------
- Added Drafts support (Feature #1326839) (richs)
2006/06/02
----------
- Updated Estonian localization and moved from ee to et
- Added Bulgarian localization
2006/05/25
----------
- Finalized GoogieSpell integration
2006/05/18
----------
- Added Arabic and Armenian localizations
- Updated Russian localization
- Removed MDB2 classes from repository. Install them seperately if used.
- Updated MDB2 wrapper class contributed by Lukas Kahwe Smith
- Allow & in e-mail addresses
2006/05/05
----------
- Fixed typos in function rcube_button() (Bugs #1473198 and #1473201)
- Check for zlib.output_compression before using ob_gzhandler (Bug #1471069)
- Casting date parts in iil_StrToTime() to avoid warnings (Bug #1482140)
- Corrected INSTALL description (Bug #1476106)
- Added charset to javascript HTTP headers
- Fixed Opera bug with CC and BCC fields (Bug #1474576)
- Changed login page title regarding product name (Bug #1476413)
- Pimped search function
- Applied attachment viewing/forwarding patches by Andrew Fladmark
- Applied prev/next patch by Leonard Bouchet
- Applied patches by Mark Bucciarelli
- Applied patch for requesting receipts by Salvatore Ansani
- Integrated GoogieSpell as suggested by phil (styling is not perfect yet, localization is missing)
2006/04/13
----------
- Added Slovenian localization
- Updated Portuguese localization
- Fixed parent.location problem for compose-links
- Added sort order saving patch by Jacob Brunson
- Added gzip compression support
2006/04/02
----------
- Added Lithuanian localization
- Improved search function
- Added version string as template object
- Load host-specific configuration file (see config/main.inc.php)
- New config parameter adding domain to user names for login
- Strip tags on _auth, _action, _task parameters
- Corrected labels for next/previous page buttons in address book
2006/03/23
----------
- Auto-detect mail header delimiters
- Regard daylight savings
- Localized quota display
- Started implementing search function
2006/03/20
----------
- Avoid error message when saving an unchanged identity (Bug #1429510)
- Fixed hard-coded cols selection for sent folder (Bug #1354586)
- Enable some HTML links for use with "open in new window" or "save target"
- Check meta-key instead of ctrl on Macs
- Ignore double clicks when holding down a modifier key
- Fixed reloading of the login page
- Fixed typo in compose template (Bug #1446852)
- Added compose button to message read step (Request #1433288)
- New config parameter for persistent database connections (Bug #1431817)
2006/03/14
----------
- Don't remove internal HTML tags in plaintext messages
- Improved error handling in DB connection failure
2006/02/22
----------
- Updated localizations
- Fixed bug #1435989
2006/02/19
----------
- Updated localizations
- Applied patch of Anders Karlsson
- Applied patch of Jacob Brunson
- Applied patch for virtuser_query by Robin Elfrink
- Added support for References header (patch by Auke)
- Added support for mbstring module by Tadashi Jokagi
- Added function for automatic remove of slashes on GET and POST vars
if magic_quotes is enabled
2006/02/05
----------
- Added Slovak, Hungarian, Bosnian and Croation translation
- 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
- Changed to full UTF-8 support
- Additional timezones (Patch #1389912)
- Added LDAP public search (experimental)
- Applied patch for correct ctrl/shift behavior for message selection (Bug #1326364)
- Casting to strings when adding empty headers to message cache (Bug #1406026)
- Skip sender-address as recipient when Reply-to-all
- Fixes in utf8-class
- Added patch for Quota display by Aury Fink Filho <nuny@aury.com.br>
- Added garbage collector for message cache
- Added patches for BCC headers
2005/12/16
----------
- Added Turkish and Simplified Chinese translation
- Use virtusertable to resolve e-mail addresses at login
- Configurable mail_domain used to compose correct e-mail addresses
on first login
2005/12/03
----------
- Added Finnish, Romanian, Polish, Czech, British, Norwegian, Greek, Russian,
Estonian and Chinese translation
- Get IMAP server capabilities in array
- Check for NAMESPACE capability before sending command
- Set default user language from config 'locale_string'
- Added sorting patch for message list
- Make default sort col/order configurable
- Fixed XSS in address book and identities
- Added more XSS protection (Bug #1308236)
- Added tab indexes for compose form
- Added 'changed' col to contacts table
- Support for 160-bit session hashes
- Added input check for contacts and identities (Patch #1346523)
- Added messages/warning to compose step (Patch #1323895)
- Added favicon to the default skin
- Fixed Bug #1334337 as far as possible
- Added Reply-To-All functionality (Request #1326395, Patch #1349777)
- Redesign of client side AJAX code (enable multi threading)
- Added keep-alive signal every minute
- Make logs dir configurable
- Added support for SMTPS
- Decode attachment file names
- Make delimiter for message headers configurable
- Add generic footer to sent messages
- Choose the rigt identity when replying
- Remove signature when replying (Request #1333167)
- Signatures for each identity
- Select charset when composing message
- Complete re-design of the caching mechanism
2005/08/11
----------
- Write list header to client even if list is empty
- Add functions "select all", "select none" to message list
- Improved filter for HTML messages to remove potentially malicious tags
(script, iframe, object) and event handlers.
- Buttons for next/previous message in view mode
- Add new created contact to list and show confirmation status
- Added folder management (subscribe/create/delete)
- Log message sending (SMTP log)
- Grant access for Camino browser
- Added German translation
2005/10/20
----------
- Added Swedish, Latvian, Portuguese and Catalan translation
- Make SMTP auth method configurable
- Make mailboxlist scrollable (Bug #1326372)
- Fixed SSL support
- Improved support for Courier IMAP (root folder and delimiter issues)
- Moved taskbar from bottom to top
- Added 'session_lifetime' parameter
- Fixed wrong unread count when deleting message (Bug #1332434)
- Srip tags when creating a new folder (Bug #1332084)
- Translate HTML tags in message headers (Bug #1330134)
- Correction in German translation (Bug #1329434)
- Display folder names with special chars correctly (Bug #1330157)
2005/10/07
----------
- Added French, Italian, Spanish, Danish, Dutch translation
- Clarified license (Bug #1305966)
- Fixed PHP warnings (Bug #1299403)
- Fixed english translation (Bug #1295406)
- Fixed bug #1290833: Last character of email not seen
- Fixed bug #1292199 when creating new user
- Allow more browsers (Bug #1285101)
- Added setting for showing pretty dates
- Added support for SQLite database
- Make use of message caching configurable
- Also add attachments when forwarding a message
- Long folder names will not flow over message list (Bug #1267232)
- Show nested mailboxes hieracically
- Enable IMAPS by host
2005/08/20
----------
- Improved cacheing of mailbox messagecount
- Fixed javascript bug when creating a new message folder
- Fixed javascript bugs #1260990 and #1260992: folder selection
- Make Trash folder configurable
- Auto create folders Inbox, Sent and Trash (if configured)
- Support for IMAP root folder
- Added support fot text/enriched messages
- Make list of special mailboxes configurable
diff --git a/INSTALL b/INSTALL
index dd52fa5f0..efe060499 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,97 +1,98 @@
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)
+ - memory_limit (increase as suitable to support large attachments)
* A MySQL or PostgreSQL database engine or the SQLite extension for PHP
* A database with permission to create tables
INSTALLATION
============
1. Decompress and put this folder somewhere inside your document root
2. Make sure that the following directories (and the files within)
are writable by the webserver
- /temp
- /logs
3. Create a new database and a database user for RoundCube (see DATABASE SETUP)
4. Create database tables using the queries in file 'SQL/*.initial.sql'
(* stands for your database type)
5. Rename the files config/*.inc.php.dist to config/*.inc.php
6. Modify the files in config/* to suit your local environment
7. Done!
DATABASE SETUP
==============
* MySQL
-------
Setting up the mysql database can be done by creating an empty database,
importing the table layout and granting the proper permissions to the
roundcube user. Here is an example of that procedure:
# mysql
> CREATE DATABASE 'roundcubemail';
> GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost
IDENTIFIED BY 'password';
> quit
# mysql roundcubemail < SQL/mysql.initial.sql
For MySQL version 4.1 and up, it's recommended to create the database for
RoundCube with the following command:
> CREATE DATABASE 'roundcubemail' DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
* SQLite
--------
Sqlite requires specifically php5 (sqlite in php4 currently doesn't
work with roundcube), and you need sqlite 2 (preferably 2.8) to setup
the sqlite db (sqlite 3.x also doesn't work at the moment). Here is
an example how you can setup the sqlite.db for roundcube:
# sqlite -init SQL/sqlite.initial.sql sqlite.db
Make sure your configuration points to the sqlite.db file and that the
webserver can write to the file.
* PostgreSQL
------------
To use RoundCube with PostgreSQL support you have to follow the next
simple steps, which have to be done with the postgres system user (or
which ever is the database superuser):
$ createuser roundcubemail
$ createdb -O roundcubemail roundcubemail
$ psql roundcubemail
roundcubemail =# ALTER USER roundcube WITH PASSWORD 'the_new_password';
roundcubemail =# \c - roundcubemail
roundcubemail => \i SQL/postgres.initial.sql
All this has been tested with PostgreSQL 8.0.x and 7.4.x. Older
versions don't have a -O option for the createdb, so if you are
using that version you'll have to change ownership of the DB later.
CONFIGURATION
=============
Change the files in config/* according your to environment and your needs.
Details about the config paramaters can be found in the config files.
UPGRADING
=========
If you already have a previous version of RoundCube installed,
please refer to the instructions in UPGRADING guide.
diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc
index d825a35b0..bb3146466 100644
--- a/program/include/rcube_imap.inc
+++ b/program/include/rcube_imap.inc
@@ -1,2134 +1,2134 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/include/rcube_imap.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| IMAP wrapper that implements the Iloha IMAP Library (IIL) |
| See http://ilohamail.org/ for details |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
/**
* 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.26
* @link http://ilohamail.org
*/
class rcube_imap
{
var $db;
var $conn;
var $root_ns = '';
var $root_dir = '';
var $mailbox = 'INBOX';
var $list_page = 1;
var $page_size = 10;
var $sort_field = 'date';
var $sort_order = 'DESC';
var $delimiter = NULL;
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();
var $skip_deleted = FALSE;
var $debug_level = 1;
/**
* Object constructor
*
* @param object Database connection
*/
function __construct($db_conn)
{
$this->db = $db_conn;
}
/**
* 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, $IMAP_USE_INTERNAL_DATE;
// 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__,
'message' => 'Open SSL not available;'), TRUE, FALSE);
$port = 143;
}
$ICL_PORT = $port;
$IMAP_USE_INTERNAL_DATE = false;
$this->conn = iil_Connect($host, $user, $pass, array('imap' => 'check'));
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->port = $port;
$this->ssl = $use_ssl;
// print trace mesages
if ($this->conn && ($this->debug_level & 8))
console($this->conn->message);
// write error log
else if (!$this->conn && $GLOBALS['iil_error'])
{
raise_error(array('code' => 403,
'type' => 'imap',
'message' => $GLOBALS['iil_error']), TRUE, FALSE);
}
// get account namespace
if ($this->conn)
{
$this->_parse_capability($this->conn->capability);
iil_C_NameSpace($this->conn);
if (!empty($this->conn->delimiter))
$this->delimiter = $this->conn->delimiter;
if (!empty($this->conn->rootdir))
{
$this->set_rootdir($this->conn->rootdir);
$this->root_ns = ereg_replace('[\.\/]$', '', $this->conn->rootdir);
}
}
return $this->conn ? TRUE : FALSE;
}
/**
* Close IMAP connection
* Usually done on script shutdown
*
* @access public
*/
function close()
{
if ($this->conn)
iil_Close($this->conn);
}
/**
* 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();
$this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl);
}
/**
* 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)==='/')
$root = substr($root, 0, -1);
$this->root_dir = $root;
if (empty($this->delimiter))
$this->get_hierarchy_delimiter();
}
/**
* 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))
{
$this->default_folders = array();
// add mailbox names lower case
foreach ($arr as $mbox_row)
$this->default_folders[] = strtolower($mbox_row);
// add inbox if not included
if (!in_array('inbox', $this->default_folders))
array_unshift($arr, 'inbox');
}
}
/**
* Set internal mailbox reference.
*
* All operations will be perfomed on this mailbox/folder
*
* @param string Mailbox/Folder name
* @access public
*/
function set_mailbox($new_mbox)
{
$mailbox = $this->_mod_mailbox($new_mbox);
if ($this->mailbox == $mailbox)
return;
$this->mailbox = $mailbox;
// clear messagecount cache for this mailbox
$this->_clear_messagecount($mailbox);
}
/**
* 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);
return $this->capabilities[$cap];
}
/**
* 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))
$this->delimiter = iil_C_GetHierarchyDelimiter($this->conn);
if (empty($this->delimiter))
$this->delimiter = '/';
return $this->delimiter;
}
/**
* 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();
$a_mboxes = $this->_list_mailboxes($root, $filter);
foreach ($a_mboxes as $mbox_row)
{
$name = $this->_mod_mailbox($mbox_row, 'out');
if (strlen($name))
$a_out[] = $name;
}
// sort mailboxes
$a_out = $this->_sort_mailbox_list($a_out);
return $a_out;
}
/**
* 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();
// get cached folder list
$a_mboxes = $this->get_cache('mailboxes');
if (is_array($a_mboxes))
return $a_mboxes;
// retrieve list of folders from IMAP server
$a_folders = iil_C_ListSubscribed($this->conn, $this->_mod_mailbox($root), $filter);
if (!is_array($a_folders) || !sizeof($a_folders))
$a_folders = array();
// create Default folders if they do not exist
global $CONFIG;
foreach ($CONFIG['default_imap_folders'] as $folder)
{
if (!in_array_nocase($folder, $a_folders))
{
$this->create_mailbox($folder, TRUE);
$this->subscribe($folder);
}
}
$a_folders = iil_C_ListSubscribed($this->conn, $this->_mod_mailbox($root), $filter);
$a_mailbox_cache = array();
// write mailboxlist to cache
$this->update_cache('mailboxes', $a_folders);
return $a_folders;
}
/**
* Get message count for a specific mailbox
*
* @param string Mailbox/folder name
* @param string Mode for count [ALL|UNSEEN|RECENT]
* @param boolean Force reading from server and update cache
* @return number Number of messages
* @access public
*/
function messagecount($mbox_name='', $mode='ALL', $force=FALSE)
{
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
return $this->_messagecount($mailbox, $mode, $force);
}
/**
* Private method for getting nr of messages
*
* @access private
* @see rcube_imap::messagecount
*/
function _messagecount($mailbox='', $mode='ALL', $force=FALSE)
{
$a_mailbox_cache = FALSE;
$mode = strtoupper($mode);
if (empty($mailbox))
$mailbox = $this->mailbox;
$a_mailbox_cache = $this->get_cache('messagecount');
// return cached value
if (!$force && is_array($a_mailbox_cache[$mailbox]) && isset($a_mailbox_cache[$mailbox][$mode]))
return $a_mailbox_cache[$mailbox][$mode];
// RECENT count is fetched abit different
if ($mode == 'RECENT')
$count = iil_C_CheckForRecent($this->conn, $mailbox);
// use SEARCH for message counting
else if ($this->skip_deleted)
{
$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]))
$a_mailbox_cache[$mailbox] = array();
$a_mailbox_cache[$mailbox][$mode] = (int)$count;
// write back to cache
$this->update_cache('messagecount', $a_mailbox_cache);
return (int)$count;
}
/**
* Public method for listing headers
* convert mailbox name with root dir first
*
* @param string Mailbox/folder name
* @param number Current page to list
* @param string Header field to sort by
* @param string Sort order [ASC|DESC]
* @return array Indexed array with message header objects
* @access public
*/
function list_headers($mbox_name='', $page=NULL, $sort_field=NULL, $sort_order=NULL)
{
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
return $this->_list_headers($mailbox, $page, $sort_field, $sort_order);
}
/**
* Private method for listing message headers
*
* @access private
* @see rcube_imap::list_headers
*/
function _list_headers($mailbox='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $recursive=FALSE)
{
if (!strlen($mailbox))
return array();
if ($sort_field!=NULL)
$this->sort_field = $sort_field;
if ($sort_order!=NULL)
$this->sort_order = strtoupper($sort_order);
$max = $this->_messagecount($mailbox);
$start_msg = ($this->list_page-1) * $this->page_size;
list($begin, $end) = $this->_get_message_range($max, $page);
/*
if ($page=='all')
{
$begin = 0;
$end = $max;
}
else if (!$this->get_capability('sort') && $this->sort_order=='DESC')
{
$begin = $max - $this->page_size - $start_msg;
$end = $max - $start_msg;
}
else
{
$begin = $start_msg;
$end = $start_msg + $this->page_size;
}
if ($begin < 0) $begin = 0;
if ($end < 0) $end = $max;
if ($end > $max) $end = $max;
*/
//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, $this->sort_field, $this->sort_order);
$headers_sorted = TRUE;
}
else
{
// retrieve headers from IMAP
if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')))
{
//console("$mailbox: ".join(',', $msg_index));
$msgs = $msg_index[$begin];
for ($i=$begin+1; $i < $end; $i++)
$msgs = $msgs.','.$msg_index[$i];
$sorted = TRUE;
}
else
{
$msgs = sprintf("%d:%d", $begin+1, $end);
$sorted = FALSE;
}
// cache is dirty, sync it
if ($this->caching_enabled && $cache_status==-1 && !$recursive)
{
$this->sync_header_index($mailbox);
return $this->_list_headers($mailbox, $page, $this->sort_field, $this->sort_order, TRUE);
}
// fetch reuested headers from server
$a_msg_headers = array();
$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);
// kick child process to sync cache
// ...
}
// return empty array if no messages found
if (!is_array($a_msg_headers) || empty($a_msg_headers))
return array();
// if not already sorted
// if (!$headers_sorted)
// $a_msg_headers = iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order);
if (!$headers_sorted && $this->sort_order == 'DESC')
$a_msg_headers = array_reverse($a_msg_headers);
return array_values($a_msg_headers);
}
/**
* Public method for listing a specific set of headers
* convert mailbox name with root dir first
*
* @param string Mailbox/folder name
* @param array List of message ids to list
* @param number Current page to list
* @param string Header field to sort by
* @param string Sort order [ASC|DESC]
* @return array Indexed array with message header objects
* @access public
*/
function list_header_set($mbox_name='', $msgs, $page=NULL, $sort_field=NULL, $sort_order=NULL)
{
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
return $this->_list_header_set($mailbox, $msgs, $page, $sort_field, $sort_order);
}
/**
* Private method for listing a set of message headers
*
* @access private
* @see rcube_imap::list_header_set
*/
function _list_header_set($mailbox, $msgs, $page=NULL, $sort_field=NULL, $sort_order=NULL)
{
// also accept a comma-separated list of message ids
if (is_string($msgs))
$msgs = split(',', $msgs);
if (!strlen($mailbox) || empty($msgs))
return array();
if ($sort_field!=NULL)
$this->sort_field = $sort_field;
if ($sort_order!=NULL)
$this->sort_order = strtoupper($sort_order);
$max = count($msgs);
$start_msg = ($this->list_page-1) * $this->page_size;
// fetch reuested headers from server
$a_msg_headers = array();
$this->_fetch_headers($mailbox, join(',', $msgs), $a_msg_headers, NULL);
// return empty array if no messages found
if (!is_array($a_msg_headers) || empty($a_msg_headers))
return array();
// if not already sorted
$a_msg_headers = iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order);
// only return the requested part of the set
return array_slice(array_values($a_msg_headers), $start_msg, min($max-$start_msg, $this->page_size));
}
/**
* Helper function to get first and last index of the requested set
*
* @param number message count
* @param mixed page number to show, or string 'all'
* @return array array with two values: first index, last index
* @access private
*/
function _get_message_range($max, $page)
{
$start_msg = ($this->list_page-1) * $this->page_size;
if ($page=='all')
{
$begin = 0;
$end = $max;
}
else if ($this->sort_order=='DESC')
{
$begin = $max - $this->page_size - $start_msg;
$end = $max - $start_msg;
}
else
{
$begin = $start_msg;
$end = $start_msg + $this->page_size;
}
if ($begin < 0) $begin = 0;
if ($end < 0) $end = $max;
if ($end > $max) $end = $max;
return array($begin, $end);
}
/**
* Fetches message headers
* Used for loop
*
* @param string Mailbox name
* @param string Message index 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_name='', $sort_field=NULL, $sort_order=NULL)
{
if ($sort_field!=NULL)
$this->sort_field = $sort_field;
if ($sort_order!=NULL)
$this->sort_order = strtoupper($sort_order);
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
$key = "$mbox:".$this->sort_field.":".$this->sort_order.".msgi";
// have stored it in RAM
if (isset($this->cache[$key]))
return $this->cache[$key];
// check local cache
$cache_key = $mailbox.'.msg';
$cache_status = $this->check_cache_status($mailbox, $cache_key);
// cache is OK
if ($cache_status>0)
{
$a_index = $this->get_message_cache_index($cache_key, TRUE, $this->sort_field, $this->sort_order);
return array_values($a_index);
}
// fetch complete message index
$msg_count = $this->_messagecount($mailbox);
if ($this->get_capability('sort') && ($a_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, '', TRUE)))
{
if ($this->sort_order == 'DESC')
$a_index = array_reverse($a_index);
$this->cache[$key] = $a_index;
}
else
{
$a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:$msg_count", $this->sort_field);
$a_uids = iil_C_FetchUIDs($this->conn, $mailbox);
if ($this->sort_order=="ASC")
asort($a_index);
else if ($this->sort_order=="DESC")
arsort($a_index);
$i = 0;
$this->cache[$key] = array();
foreach ($a_index as $index => $value)
$this->cache[$key][$i++] = $a_uids[$index];
}
return $this->cache[$key];
}
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);
}
}
/**
* Invoke search request to IMAP server
*
* @param string mailbox name to search in
* @param string search criteria (ALL, TO, FROM, SUBJECT, etc)
* @param string search string
* @return array search results as list of message ids
* @access public
*/
function search($mbox_name='', $criteria='ALL', $str=NULL)
{
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
if ($str && $criteria)
{
$criteria = 'CHARSET UTF-8 '.$criteria.' "'.UTF7EncodeString($str).'"';
return $this->_search_index($mailbox, $criteria);
}
else
return $this->_search_index($mailbox, $criteria);
}
/**
* Private search method
*
* @return array search results as list of message ids
* @access private
* @see rcube_imap::search()
*/
function _search_index($mailbox, $criteria='ALL')
{
$a_messages = iil_C_Search($this->conn, $mailbox, $criteria);
// clean message list (there might be some empty entries)
if (is_array($a_messages))
{
foreach ($a_messages as $i => $val)
if (empty($val))
unset($a_messages[$i]);
}
return $a_messages;
}
function get_headers($id, $mbox_name=NULL, $is_uid=TRUE)
{
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
// get cached headers
if ($is_uid && ($headers = $this->get_cached_message($mailbox.'.msg', $id)))
return $headers;
$msg_id = $is_uid ? $this->_uid2id($id) : $id;
$headers = iil_C_FetchHeader($this->conn, $mailbox, $msg_id);
// write headers cache
if ($headers)
$this->add_message_cache($mailbox.'.msg', $msg_id, $headers);
return $headers;
}
function get_body($uid, $part=1)
{
if (!($msg_id = $this->_uid2id($uid)))
return FALSE;
$structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id);
$structure = iml_GetRawStructureArray($structure_str);
$body = iil_C_FetchPartBody($this->conn, $this->mailbox, $msg_id, $part);
$encoding = iml_GetPartEncodingCode($structure, $part);
if ($encoding==3) $body = $this->mime_decode($body, 'base64');
else if ($encoding==4) $body = $this->mime_decode($body, 'quoted-printable');
return $body;
}
function get_raw_body($uid)
{
if (!($msg_id = $this->_uid2id($uid)))
return FALSE;
$body = iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL);
$body .= iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 1);
return $body;
}
// set message flag to one or several messages
// possible flags are: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT
function set_flag($uids, $flag)
{
$flag = strtoupper($flag);
$msg_ids = array();
if (!is_array($uids))
$uids = explode(',',$uids);
foreach ($uids as $uid) {
$msg_ids[$uid] = $this->_uid2id($uid);
}
if ($flag=='UNDELETED')
$result = iil_C_Undelete($this->conn, $this->mailbox, join(',', array_values($msg_ids)));
else if ($flag=='UNSEEN')
$result = iil_C_Unseen($this->conn, $this->mailbox, join(',', array_values($msg_ids)));
else
$result = iil_C_Flag($this->conn, $this->mailbox, join(',', array_values($msg_ids)), $flag);
// reload message headers if cached
$cache_key = $this->mailbox.'.msg';
if ($this->caching_enabled)
{
foreach ($msg_ids as $uid => $id)
{
if ($cached_headers = $this->get_cached_message($cache_key, $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
$count = count($msg_ids);
// clear message count cache
if ($result && $flag=='SEEN')
$this->_set_messagecount($this->mailbox, 'UNSEEN', $count*(-1));
else if ($result && $flag=='UNSEEN')
$this->_set_messagecount($this->mailbox, 'UNSEEN', $count);
else if ($result && $flag=='DELETED')
$this->_set_messagecount($this->mailbox, 'ALL', $count*(-1));
return $result;
}
// append a mail message (source) to a specific mailbox
function save_message($mbox_name, &$message)
{
$mbox_name = stripslashes($mbox_name);
$mailbox = $this->_mod_mailbox($mbox_name);
// make sure 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
$this->_set_messagecount($mailbox, 'ALL', 1);
}
return $saved;
}
// move a message from one mailbox to another
function move_message($uids, $to_mbox, $from_mbox='')
{
$to_mbox = stripslashes($to_mbox);
$from_mbox = stripslashes($from_mbox);
$to_mbox = $this->_mod_mailbox($to_mbox);
$from_mbox = $from_mbox ? $this->_mod_mailbox($from_mbox) : $this->mailbox;
// make sure mailbox exists
if (!in_array($to_mbox, $this->_list_mailboxes()))
{
if (in_array(strtolower($to_mbox), $this->default_folders))
$this->create_mailbox($to_mbox, TRUE);
else
return FALSE;
}
// convert the list of uids to array
$a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL);
// exit if no message uids are specified
if (!is_array($a_uids))
return false;
// convert uids to message ids
$a_mids = array();
foreach ($a_uids as $uid)
$a_mids[] = $this->_uid2id($uid, $from_mbox);
$moved = iil_C_Move($this->conn, join(',', $a_mids), $from_mbox, $to_mbox);
// send expunge command in order to have the moved message
// really deleted from the source mailbox
if ($moved)
{
$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_cache_index = $this->get_message_cache_index($cache_key)))
{
$start_index = 100000;
foreach ($a_uids as $uid)
{
- $index = array_search($uid, $a_cache_index);
- $start_index = min($index, $start_index);
+ if(($index = array_search($uid, $a_cache_index)) !== FALSE)
+ $start_index = min($index, $start_index);
}
// clear cache from the lowest index on
$this->clear_message_cache($cache_key, $start_index);
}
return $moved;
}
// mark messages as deleted and expunge mailbox
function delete_message($uids, $mbox_name='')
{
$mbox_name = stripslashes($mbox_name);
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
// convert the list of uids to array
$a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL);
// exit if no message uids are specified
if (!is_array($a_uids))
return false;
// convert uids to message ids
$a_mids = array();
foreach ($a_uids as $uid)
$a_mids[] = $this->_uid2id($uid, $mailbox);
$deleted = iil_C_Delete($this->conn, $mailbox, join(',', $a_mids));
// send expunge command in order to have the deleted message
// really deleted from the mailbox
if ($deleted)
{
$this->_expunge($mailbox, FALSE);
$this->_clear_messagecount($mailbox);
}
// remove deleted messages from cache
$cache_key = $mailbox.'.msg';
if ($deleted && ($a_cache_index = $this->get_message_cache_index($cache_key)))
{
$start_index = 100000;
foreach ($a_uids as $uid)
{
$index = array_search($uid, $a_cache_index);
$start_index = min($index, $start_index);
}
// clear cache from the lowest index on
$this->clear_message_cache($cache_key, $start_index);
}
return $deleted;
}
// clear all messages in a specific mailbox
function clear_mailbox($mbox_name=NULL)
{
$mbox_name = stripslashes($mbox_name);
$mailbox = !empty($mbox_name) ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
$msg_count = $this->_messagecount($mailbox, 'ALL');
if ($msg_count>0)
{
$cleared = iil_C_ClearFolder($this->conn, $mailbox);
// make sure the message count cache is cleared as well
if ($cleared)
{
$this->clear_message_cache($mailbox.'.msg');
$a_mailbox_cache = $this->get_cache('messagecount');
unset($a_mailbox_cache[$mailbox]);
$this->update_cache('messagecount', $a_mailbox_cache);
}
return $cleared;
}
else
return 0;
}
// send IMAP expunge command and clear cache
function expunge($mbox_name='', $clear_cache=TRUE)
{
$mbox_name = stripslashes($mbox_name);
$mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $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_message_cache($mailbox.'.msg');
$this->_clear_messagecount($mailbox);
}
return $result;
}
/* --------------------------------
* folder managment
* --------------------------------*/
// return an array with all folders available in IMAP server
function list_unsubscribed($root='')
{
static $sa_unsubscribed;
if (is_array($sa_unsubscribed))
return $sa_unsubscribed;
// retrieve list of folders from IMAP server
$a_mboxes = iil_C_ListMailboxes($this->conn, $this->_mod_mailbox($root), '*');
// modify names with root dir
foreach ($a_mboxes as $mbox_name)
{
$name = $this->_mod_mailbox($mbox_name, 'out');
if (strlen($name))
$a_folders[] = $name;
}
// filter folders and sort them
$sa_unsubscribed = $this->_sort_mailbox_list($a_folders);
return $sa_unsubscribed;
}
/**
* Get quota
* added by Nuny
*/
function get_quota()
{
if ($this->get_capability('QUOTA'))
{
$result = iil_C_GetQuota($this->conn);
if ($result["total"])
return sprintf("%.2fMB / %.2fMB (%.0f%%)", $result["used"] / 1000.0, $result["total"] / 1000.0, $result["percent"]);
}
return FALSE;
}
// subscribe to a specific mailbox(es)
function subscribe($mbox_name, $mode='subscribe')
{
if (is_array($mbox_name))
$a_mboxes = $mbox_name;
else if (is_string($mbox_name) && strlen($mbox_name))
$a_mboxes = explode(',', $mbox_name);
// let this common function do the main work
return $this->_change_subscription($a_mboxes, 'subscribe');
}
// unsubscribe mailboxes
function unsubscribe($mbox_name)
{
if (is_array($mbox_name))
$a_mboxes = $mbox_name;
else if (is_string($mbox_name) && strlen($mbox_name))
$a_mboxes = explode(',', $mbox_name);
// let this common function do the main work
return $this->_change_subscription($a_mboxes, 'unsubscribe');
}
// create a new mailbox on the server and register it in local cache
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($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache)))
$result = iil_C_CreateFolder($this->conn, $abs_name);
// update mailboxlist cache
if ($result && $subscribe)
$this->subscribe($name_enc);
return $result ? $name : FALSE;
}
// set a new name to an existing mailbox
function rename_mailbox($mbox_name, $new_name, $subscribe=TRUE)
{
$result = FALSE;
// replace backslashes
$name = preg_replace('/[\\\]+/', '-', $new_name);
$name_enc = UTF7EncodeString($new_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($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache)))
$result = iil_C_RenameFolder($this->conn, $mbox_name, $abs_name);
// update mailboxlist cache
if ($result && $subscribe)
$this->unsubscribe($mbox_name);
$this->subscribe($name_enc);
return $result ? $name : FALSE;
}
// remove mailboxes from server
function delete_mailbox($mbox_name)
{
$deleted = FALSE;
if (is_array($mbox_name))
$a_mboxes = $mbox_name;
else if (is_string($mbox_name) && strlen($mbox_name))
$a_mboxes = explode(',', $mbox_name);
if (is_array($a_mboxes))
foreach ($a_mboxes as $mbox_name)
{
$mailbox = $this->_mod_mailbox($mbox_name);
// unsubscribe mailbox before deleting
iil_C_UnSubscribe($this->conn, $mailbox);
// send delete command to server
$result = iil_C_DeleteFolder($this->conn, $mailbox);
if ($result>=0)
$deleted = TRUE;
}
// clear mailboxlist cache
if ($deleted)
{
$this->clear_message_cache($mailbox.'.msg');
$this->clear_cache('mailboxes');
}
return $deleted;
}
/* --------------------------------
* internal caching methods
* --------------------------------*/
function set_caching($set)
{
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 = $this->_read_cache_record('IMAP.'.$key);
$this->cache[$key] = strlen($cache_data) ? unserialize($cache_data) : FALSE;
}
return $this->cache[$key];
}
function update_cache($key, $data)
{
$this->cache[$key] = $data;
$this->cache_changed = TRUE;
$this->cache_changes[$key] = TRUE;
}
function write_cache()
{
if ($this->caching_enabled && $this->cache_changed)
{
foreach ($this->cache as $key => $data)
{
if ($this->cache_changes[$key])
$this->_write_cache_record('IMAP.'.$key, serialize($data));
}
}
}
function clear_cache($key=NULL)
{
if ($key===NULL)
{
foreach ($this->cache as $key => $data)
$this->_clear_cache_record('IMAP.'.$key);
$this->cache = array();
$this->cache_changed = FALSE;
$this->cache_changes = array();
}
else
{
$this->_clear_cache_record('IMAP.'.$key);
$this->cache_changes[$key] = FALSE;
unset($this->cache[$key]);
}
}
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 highest message matches -> cache seems OK
if ($cache_uid == $header->uid)
return 1;
// cache is dirty
return -1;
}
// if cache count differs less than 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, $sort_col='idx', $sort_order='ASC')
{
static $sa_message_index = array();
// empty key -> empty array
if (empty($key))
return 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 ".$this->db->quote_identifier($sort_col)." ".$sort_order,
$_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)
{
if (!$key || !is_object($headers) || empty($headers->uid))
return;
$this->db->query(
"INSERT INTO ".get_table_name('messages')."
(user_id, del, cache_key, created, idx, uid, subject, ".$this->db->quoteIdentifier('from').", ".$this->db->quoteIdentifier('to').", cc, date, size, headers)
VALUES (?, 0, ?, now(), ?, ?, ?, ?, ?, ?, ".$this->db->fromunixtime($headers->timestamp).", ?, ?)",
$_SESSION['user_id'],
$key,
$index,
$headers->uid,
(string)substr($this->decode_header($headers->subject, TRUE), 0, 128),
(string)substr($this->decode_header($headers->from, TRUE), 0, 128),
(string)substr($this->decode_header($headers->to, TRUE), 0, 128),
(string)substr($this->decode_header($headers->cc, TRUE), 0, 128),
(int)$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 methods
* --------------------------------*/
function decode_address_list($input, $max=NULL)
{
$a = $this->_parse_address_list($input);
$out = array();
if (!is_array($a))
return $out;
$c = count($a);
$j = 0;
foreach ($a as $val)
{
$j++;
$address = $val['address'];
$name = preg_replace(array('/^[\'"]/', '/[\'"]$/'), '', trim($val['name']));
$string = $name!==$address ? sprintf('%s <%s>', strpos($name, ',')!==FALSE ? '"'.$name.'"' : $name, $address) : $address;
$out[$j] = array('name' => $name,
'mailto' => $address,
'string' => $string);
if ($max && $j==$max)
break;
}
return $out;
}
function decode_header($input, $remove_quotes=FALSE)
{
$str = $this->decode_mime_string((string)$input);
if ($str{0}=='"' && $remove_quotes)
{
$str = str_replace('"', '', $str);
}
return $str;
}
/**
* Decode a mime-encoded string to internal charset
*
* @access static
*/
function decode_mime_string($input)
{
$out = '';
$pos = strpos($input, '=?');
if ($pos !== false)
{
$out = substr($input, 0, $pos);
$end_cs_pos = strpos($input, "?", $pos+2);
$end_en_pos = strpos($input, "?", $end_cs_pos+1);
$end_pos = strpos($input, "?=", $end_en_pos+1);
$encstr = substr($input, $pos+2, ($end_pos-$pos-2));
$rest = substr($input, $end_pos+2);
$out .= rcube_imap::_decode_mime_string_part($encstr);
$out .= rcube_imap::decode_mime_string($rest);
return $out;
}
// no encoding information, defaults to what is specified in the class header
return rcube_charset_convert($input, 'ISO-8859-1');
}
/**
* Decode a part of a mime-encoded string
*
* @access static
*/
function _decode_mime_string_part($str)
{
$a = explode('?', $str);
$count = count($a);
// should be in format "charset?encoding?base64_string"
if ($count >= 3)
{
for ($i=2; $i<$count; $i++)
$rest.=$a[$i];
if (($a[1]=="B")||($a[1]=="b"))
$rest = base64_decode($rest);
else if (($a[1]=="Q")||($a[1]=="q"))
{
$rest = str_replace("_", " ", $rest);
$rest = quoted_printable_decode($rest);
}
return rcube_charset_convert($rest, $a[0]);
}
else
return $str; // we dont' know what to do with this
}
function mime_decode($input, $encoding='7bit')
{
switch (strtolower($encoding))
{
case '7bit':
return $input;
break;
case 'quoted-printable':
return quoted_printable_decode($input);
break;
case 'base64':
return base64_decode($input);
break;
default:
return $input;
}
}
function mime_encode($input, $encoding='7bit')
{
switch ($encoding)
{
case 'quoted-printable':
return quoted_printable_encode($input);
break;
case 'base64':
return base64_encode($input);
break;
default:
return $input;
}
}
// convert body chars according to the ctype_parameters
function charset_decode($body, $ctype_param)
{
if (is_array($ctype_param) && !empty($ctype_param['charset']))
return rcube_charset_convert($body, $ctype_param['charset']);
// defaults to what is specified in the class header
return rcube_charset_convert($body, 'ISO-8859-1');
}
/* --------------------------------
* private methods
* --------------------------------*/
function _mod_mailbox($mbox_name, $mode='in')
{
if ((!empty($this->root_ns) && $this->root_ns == $mbox_name) || ($mbox_name == 'INBOX' && $mode == 'in'))
return $mbox_name;
if (!empty($this->root_dir) && $mode=='in')
$mbox_name = $this->root_dir.$this->delimiter.$mbox_name;
else if (strlen($this->root_dir) && $mode=='out')
$mbox_name = substr($mbox_name, strlen($this->root_dir)+1);
return $mbox_name;
}
// sort mailboxes first by default folders and then in alphabethical order
function _sort_mailbox_list($a_folders)
{
$a_out = $a_defaults = array();
// find default folders and skip folders starting with '.'
foreach($a_folders as $i => $folder)
{
if ($folder{0}=='.')
continue;
if (($p = array_search(strtolower($folder), $this->default_folders))!==FALSE)
$a_defaults[$p] = $folder;
else
$a_out[] = $folder;
}
sort($a_out);
ksort($a_defaults);
return array_merge($a_defaults, $a_out);
}
function get_id($uid, $mbox_name=NULL)
{
return $this->_uid2id($uid, $mbox_name);
}
function get_uid($id,$mbox_name=NULL)
{
return $this->_id2uid($id, $mbox_name);
}
function _uid2id($uid, $mbox_name=NULL)
{
if (!$mbox_name)
$mbox_name = $this->mailbox;
if (!isset($this->uid_id_map[$mbox_name][$uid]))
$this->uid_id_map[$mbox_name][$uid] = iil_C_UID2ID($this->conn, $mbox_name, $uid);
return $this->uid_id_map[$mbox_name][$uid];
}
function _id2uid($id, $mbox_name=NULL)
{
if (!$mbox_name)
$mbox_name = $this->mailbox;
return iil_C_ID2UID($this->conn, $mbox_name, $id);
}
// 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)
{
$updated = FALSE;
if (is_array($a_mboxes))
foreach ($a_mboxes as $i => $mbox_name)
{
$mailbox = $this->_mod_mailbox($mbox_name);
$a_mboxes[$i] = $mailbox;
if ($mode=='subscribe')
$result = iil_C_Subscribe($this->conn, $mailbox);
else if ($mode=='unsubscribe')
$result = iil_C_UnSubscribe($this->conn, $mailbox);
if ($result>=0)
$updated = TRUE;
}
// get cached mailbox list
if ($updated)
{
$a_mailbox_cache = $this->get_cache('mailboxes');
if (!is_array($a_mailbox_cache))
return $updated;
// modify cached list
if ($mode=='subscribe')
$a_mailbox_cache = array_merge($a_mailbox_cache, $a_mboxes);
else if ($mode=='unsubscribe')
$a_mailbox_cache = array_diff($a_mailbox_cache, $a_mboxes);
// write mailboxlist to cache
$this->update_cache('mailboxes', $this->_sort_mailbox_list($a_mailbox_cache));
}
return $updated;
}
// increde/decrese messagecount for a specific mailbox
function _set_messagecount($mbox_name, $mode, $increment)
{
$a_mailbox_cache = FALSE;
$mailbox = $mbox_name ? $mbox_name : $this->mailbox;
$mode = strtoupper($mode);
$a_mailbox_cache = $this->get_cache('messagecount');
if (!is_array($a_mailbox_cache[$mailbox]) || !isset($a_mailbox_cache[$mailbox][$mode]) || !is_numeric($increment))
return FALSE;
// add incremental value to messagecount
$a_mailbox_cache[$mailbox][$mode] += $increment;
// there's something wrong, delete from cache
if ($a_mailbox_cache[$mailbox][$mode] < 0)
unset($a_mailbox_cache[$mailbox][$mode]);
// write back to cache
$this->update_cache('messagecount', $a_mailbox_cache);
return TRUE;
}
// remove messagecount of a specific mailbox from cache
function _clear_messagecount($mbox_name='')
{
$a_mailbox_cache = FALSE;
$mailbox = $mbox_name ? $mbox_name : $this->mailbox;
$a_mailbox_cache = $this->get_cache('messagecount');
if (is_array($a_mailbox_cache[$mailbox]))
{
unset($a_mailbox_cache[$mailbox]);
$this->update_cache('messagecount', $a_mailbox_cache);
}
}
function _parse_address_list($str)
{
$a = $this->_explode_quoted_string(',', $str);
$result = array();
foreach ($a as $key => $val)
{
$val = str_replace("\"<", "\" <", $val);
$sub_a = $this->_explode_quoted_string(' ', $val);
foreach ($sub_a as $k => $v)
{
if ((strpos($v, '@') > 0) && (strpos($v, '.') > 0))
$result[$key]['address'] = str_replace('<', '', str_replace('>', '', $v));
else
$result[$key]['name'] .= (empty($result[$key]['name'])?'':' ').str_replace("\"",'',stripslashes($v));
}
if (empty($result[$key]['name']))
$result[$key]['name'] = $result[$key]['address'];
$result[$key]['name'] = $this->decode_header($result[$key]['name']);
}
return $result;
}
function _explode_quoted_string($delimiter, $string)
{
$quotes = explode("\"", $string);
foreach ($quotes as $key => $val)
if (($key % 2) == 1)
$quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]);
$string = implode("\"", $quotes);
$result = explode($delimiter, $string);
foreach ($result as $key => $val)
$result[$key] = str_replace("_!@!_", $delimiter, $result[$key]);
return $result;
}
}
function quoted_printable_encode($input="", $line_max=76, $space_conv=false)
{
$hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
$lines = preg_split("/(?:\r\n|\r|\n)/", $input);
$eol = "\r\n";
$escape = "=";
$output = "";
while( list(, $line) = each($lines))
{
//$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary
$linlen = strlen($line);
$newline = "";
for($i = 0; $i < $linlen; $i++)
{
$c = substr( $line, $i, 1 );
$dec = ord( $c );
if ( ( $i == 0 ) && ( $dec == 46 ) ) // convert first point in the line into =2E
{
$c = "=2E";
}
if ( $dec == 32 )
{
if ( $i == ( $linlen - 1 ) ) // convert space at eol only
{
$c = "=20";
}
else if ( $space_conv )
{
$c = "=20";
}
}
else if ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) // always encode "\t", which is *not* required
{
$h2 = floor($dec/16);
$h1 = floor($dec%16);
$c = $escape.$hex["$h2"].$hex["$h1"];
}
if ( (strlen($newline) + strlen($c)) >= $line_max ) // CRLF is not counted
{
$output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
$newline = "";
// check if newline first character will be point or not
if ( $dec == 46 )
{
$c = "=2E";
}
}
$newline .= $c;
} // end of for
$output .= $newline.$eol;
} // end of while
return trim($output);
}
?>
diff --git a/program/js/app.js b/program/js/app.js
index fb103bf43..174920cc8 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -1,3633 +1,3638 @@
/*
+-----------------------------------------------------------------------+
| RoundCube Webmail Client Script |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005, RoundCube Dev, - Switzerland |
| Licensed under the GNU GPL |
| |
+-----------------------------------------------------------------------+
| Authors: Thomas Bruederli <roundcube@gmail.com> |
| Charles McNulty <charles@charlesmcnulty.com> |
+-----------------------------------------------------------------------+
$Id$
*/
// Constants
var CONTROL_KEY = 1;
var SHIFT_KEY = 2;
var CONTROL_SHIFT_KEY = 3;
var rcube_webmail_client;
function rcube_webmail()
{
this.env = new Object();
this.labels = new Object();
this.buttons = new Object();
this.gui_objects = new Object();
this.commands = new Object();
this.selection = new Array();
this.last_selected = 0;
this.in_message_list = false;
// create public reference to myself
rcube_webmail_client = this;
this.ref = 'rcube_webmail_client';
// webmail client settings
this.dblclick_time = 600;
this.message_time = 5000;
this.request_timeout = 180000;
this.kepp_alive_interval = 60000;
this.mbox_expression = new RegExp('[^0-9a-z\-_]', 'gi');
this.env.blank_img = 'skins/default/images/blank.gif';
// mimetypes supported by the browser (default settings)
this.mimetypes = new Array('text/plain', 'text/html', 'text/xml',
'image/jpeg', 'image/gif', 'image/png',
'application/x-javascript', 'application/pdf',
'application/x-shockwave-flash');
// set environment variable
this.set_env = function(name, value)
{
//if (!this.busy)
this.env[name] = value;
};
// add a localized label to the client environment
this.add_label = function(key, value)
{
this.labels[key] = value;
};
// add a button to the button list
this.register_button = function(command, id, type, act, sel, over)
{
if (!this.buttons[command])
this.buttons[command] = new Array();
var button_prop = {id:id, type:type};
if (act) button_prop.act = act;
if (sel) button_prop.sel = sel;
if (over) button_prop.over = over;
this.buttons[command][this.buttons[command].length] = button_prop;
};
// register a specific gui object
this.gui_object = function(name, id)
{
this.gui_objects[name] = id;
};
// initialize webmail client
this.init = function()
{
this.task = this.env.task;
// check browser
if (!bw.dom || !bw.xmlhttp_test())
{
location.href = this.env.comm_path+'&_action=error&_code=0x199';
return;
}
// find all registered gui objects
for (var n in this.gui_objects)
this.gui_objects[n] = rcube_find_object(this.gui_objects[n]);
// tell parent window that this frame is loaded
if (this.env.framed && parent.rcmail && parent.rcmail.set_busy)
parent.rcmail.set_busy(false);
// enable general commands
this.enable_command('logout', 'mail', 'addressbook', 'settings', true);
switch (this.task)
{
case 'mail':
var msg_list_frame = this.gui_objects.mailcontframe;
var msg_list = this.gui_objects.messagelist;
if (msg_list)
{
msg_list_frame.onmousedown = function(e){return rcube_webmail_client.click_on_list(e);};
this.init_messagelist(msg_list);
this.enable_command('toggle_status', true);
}
// enable mail commands
this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', true);
if (this.env.action=='show')
{
this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'viewsource', 'print', 'load-attachment', true);
if (this.env.next_uid)
this.enable_command('nextmessage', true);
if (this.env.prev_uid)
this.enable_command('previousmessage', true);
}
if (this.env.action=='show' && this.env.blockedobjects)
{
if (this.gui_objects.remoteobjectsmsg)
this.gui_objects.remoteobjectsmsg.style.display = 'block';
this.enable_command('load-images', true);
}
if (this.env.action=='compose')
{
this.enable_command('add-attachment', 'send-attachment', 'remove-attachment', 'send', true);
if (this.env.spellcheck)
this.enable_command('spellcheck', true);
if (this.env.drafts_mailbox)
this.enable_command('savedraft', true);
}
if (this.env.messagecount)
this.enable_command('select-all', 'select-none', 'sort', 'expunge', true);
if (this.env.messagecount && this.env.mailbox==this.env.trash_mailbox)
this.enable_command('purge', true);
this.set_page_buttons();
// focus this window
window.focus();
// init message compose form
if (this.env.action=='compose')
this.init_messageform();
// 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;
case 'addressbook':
var contacts_list = this.gui_objects.contactslist;
var ldap_contacts_list = this.gui_objects.ldapcontactslist;
if (contacts_list)
this.init_contactslist(contacts_list);
if (ldap_contacts_list)
this.init_ldapsearchlist(ldap_contacts_list);
this.set_page_buttons();
if (this.env.cid)
this.enable_command('show', 'edit', true);
if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform)
this.enable_command('save', true);
this.enable_command('list', 'add', true);
this.enable_command('ldappublicsearch', this.env.ldappublicsearch);
break;
case 'settings':
this.enable_command('preferences', 'identities', 'save', 'folders', true);
if (this.env.action=='identities' || this.env.action=='edit-identity' || this.env.action=='add-identity')
this.enable_command('edit', 'add', 'delete', true);
if (this.env.action=='edit-identity' || this.env.action=='add-identity')
this.enable_command('save', true);
if (this.env.action=='folders')
this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', 'delete-folder', true);
var identities_list = this.gui_objects.identitieslist;
if (identities_list)
this.init_identitieslist(identities_list);
break;
case 'login':
var input_user = rcube_find_object('_user');
var input_pass = rcube_find_object('_pass');
if (input_user && input_user.value=='')
input_user.focus();
else if (input_pass)
input_pass.focus();
this.enable_command('login', true);
break;
default:
break;
}
// enable basic commands
this.enable_command('logout', true);
// disable browser's contextmenus
// document.oncontextmenu = function(){ return false; }
// load body click event
document.onmousedown = function(){ return rcube_webmail_client.reset_click(); };
document.onkeydown = function(e){ return rcube_webmail_client.key_pressed(e, msg_list_frame); };
// flag object as complete
this.loaded = true;
// show message
if (this.pending_message)
this.display_message(this.pending_message[0], this.pending_message[1]);
// start interval for keep-alive/recent_check signal
if (this.kepp_alive_interval && this.task=='mail' && this.gui_objects.messagelist)
this.kepp_alive_int = setInterval(this.ref+'.check_for_recent()', this.kepp_alive_interval);
else if (this.task!='login')
this.kepp_alive_int = setInterval(this.ref+'.send_keep_alive()', this.kepp_alive_interval);
};
// reset last clicked if user clicks on anything other than the message table
this.reset_click = function() {
this.in_message_list = false;
for (var n=0; n<this.selection.length; n++) {
id = this.selection[n];
if (this.list_rows[id].obj) {
this.set_classname(this.list_rows[id].obj, 'selected', false);
this.set_classname(this.list_rows[id].obj, 'unfocused', true);
}
}
};
this.click_on_list = function(e)
{
if (!e)
e = window.event;
for (var n=0; n<this.selection.length; n++) {
id = this.selection[n];
if (this.list_rows[id].obj) {
this.set_classname(this.list_rows[id].obj, 'selected', true);
this.set_classname(this.list_rows[id].obj, 'unfocused', false);
}
}
this.in_message_list = true;
e.cancelBubble = true;
};
this.key_pressed = function(e, msg_list_frame) {
if (this.in_message_list != true)
return true;
var keyCode = document.layers ? e.which : document.all ? event.keyCode : document.getElementById ? e.keyCode : 0;
var mod_key = this.get_modifier(e);
switch (keyCode) {
case 13:
this.command('show','',this);
break;
case 40:
case 38:
return this.use_arrow_key(keyCode, mod_key, msg_list_frame);
break;
case 46:
return this.use_delete_key(keyCode, mod_key, msg_list_frame);
break;
default:
return true;
}
return true;
}
this.use_arrow_key = function(keyCode, mod_key, msg_list_frame) {
var scroll_to = 0;
if (keyCode == 40) { // down arrow key pressed
new_row = this.get_next_row();
if (!new_row) return false;
scroll_to = (Number(new_row.offsetTop) + Number(new_row.offsetHeight)) - Number(msg_list_frame.offsetHeight);
} else if (keyCode == 38) { // up arrow key pressed
new_row = this.get_prev_row();
if (!new_row) return false;
scroll_to = new_row.offsetTop;
} else {return true;}
this.select_row(new_row.uid,mod_key,true);
if (((Number(new_row.offsetTop)) < (Number(msg_list_frame.scrollTop))) ||
((Number(new_row.offsetTop) + Number(new_row.offsetHeight)) > (Number(msg_list_frame.scrollTop) + Number(msg_list_frame.offsetHeight)))) {
msg_list_frame.scrollTop = scroll_to;
}
return false;
};
this.use_delete_key = function(keyCode, mod_key, msg_list_frame){
this.command('delete','',this);
return false;
}
// get all message rows from HTML table and init each row
this.init_messagelist = function(msg_list)
{
if (msg_list && msg_list.tBodies[0])
{
this.message_rows = new Array();
var row;
for(var r=0; r<msg_list.tBodies[0].childNodes.length; r++)
{
row = msg_list.tBodies[0].childNodes[r];
while (row && (row.nodeType != 1 || row.style.display == 'none')) {
row = row.nextSibling;
r++;
}
//row = msg_list.tBodies[0].rows[r];
if (row) this.init_message_row(row);
}
}
// alias to common rows array
this.list_rows = this.message_rows;
};
// make references in internal array and set event handlers
this.init_message_row = function(row)
{
var uid, msg_icon;
if (String(row.id).match(/rcmrow([0-9]+)/))
{
uid = RegExp.$1;
row.uid = uid;
this.message_rows[uid] = {id:row.id, obj:row,
classname:row.className,
deleted:this.env.messages[uid] ? this.env.messages[uid].deleted : null,
unread:this.env.messages[uid] ? this.env.messages[uid].unread : null,
replied:this.env.messages[uid] ? this.env.messages[uid].replied : null};
// set eventhandlers to table row
row.onmousedown = function(e){ return rcube_webmail_client.drag_row(e, this.uid); };
row.onmouseup = function(e){ return rcube_webmail_client.click_row(e, this.uid); };
if (document.all)
row.onselectstart = function() { return false; };
// set eventhandler to message icon
if ((msg_icon = row.cells[0].childNodes[0]) && row.cells[0].childNodes[0].nodeName=='IMG')
{
msg_icon.id = 'msgicn_'+uid;
msg_icon._row = row;
msg_icon.onmousedown = function(e) { rcube_webmail_client.command('toggle_status', this); };
// get message icon and save original icon src
this.message_rows[uid].icon = msg_icon;
}
}
};
// init message compose form: set focus and eventhandlers
this.init_messageform = function()
{
if (!this.gui_objects.messageform)
return false;
//this.messageform = this.gui_objects.messageform;
var input_from = rcube_find_object('_from');
var input_to = rcube_find_object('_to');
var input_cc = rcube_find_object('_cc');
var input_bcc = rcube_find_object('_bcc');
var input_replyto = rcube_find_object('_replyto');
var input_subject = rcube_find_object('_subject');
var input_message = rcube_find_object('_message');
// init live search events
if (input_to)
this.init_address_input_events(input_to);
if (input_cc)
this.init_address_input_events(input_cc);
if (input_bcc)
this.init_address_input_events(input_bcc);
// add signature according to selected identity
if (input_from && input_from.type=='select-one')
this.change_identity(input_from);
if (input_to && input_to.value=='')
input_to.focus();
else if (input_subject && input_subject.value=='')
input_subject.focus();
else if (input_message)
this.set_caret2start(input_message); // input_message.focus();
// get summary of all field values
this.cmp_hash = this.compose_field_hash();
};
this.init_address_input_events = function(obj)
{
var handler = function(e){ return rcube_webmail_client.ksearch_keypress(e,this); };
var handler2 = function(e){ return rcube_webmail_client.ksearch_blur(e,this); };
if (bw.safari)
{
obj.addEventListener('keydown', handler, false);
// obj.addEventListener('blur', handler2, false);
}
else if (bw.mz)
{
obj.addEventListener('keypress', handler, false);
obj.addEventListener('blur', handler2, false);
}
else if (bw.ie)
{
obj.onkeydown = handler;
//obj.attachEvent('onkeydown', handler);
// obj.attachEvent('onblur', handler2, false);
}
obj.setAttribute('autocomplete', 'off');
};
// get all contact rows from HTML table and init each row
this.init_contactslist = function(contacts_list)
{
if (contacts_list && contacts_list.tBodies[0])
{
this.contact_rows = new Array();
var row;
for(var r=0; r<contacts_list.tBodies[0].childNodes.length; r++)
{
row = contacts_list.tBodies[0].childNodes[r];
this.init_table_row(row, 'contact_rows');
}
}
// alias to common rows array
this.list_rows = this.contact_rows;
if (this.env.cid)
this.highlight_row(this.env.cid);
};
// get all contact rows from HTML table and init each row
this.init_ldapsearchlist = function(ldap_contacts_list)
{
if (ldap_contacts_list && ldap_contacts_list.tBodies[0])
{
this.ldap_contact_rows = new Array();
var row;
for(var r=0; r<ldap_contacts_list.tBodies[0].childNodes.length; r++)
{
row = ldap_contacts_list.tBodies[0].childNodes[r];
this.init_table_row(row, 'ldap_contact_rows');
}
}
// alias to common rows array
this.list_rows = this.ldap_contact_rows;
};
// make references in internal array and set event handlers
this.init_table_row = function(row, array_name)
{
var cid;
if (String(row.id).match(/rcmrow([0-9]+)/))
{
cid = RegExp.$1;
row.cid = cid;
this[array_name][cid] = {id:row.id,
obj:row,
classname:row.className};
// set eventhandlers to table row
row.onmousedown = function(e) { rcube_webmail_client.in_selection_before=this.cid; return false; }; // fake for drag handler
row.onmouseup = function(e){ return rcube_webmail_client.click_row(e, this.cid); };
}
};
// get all contact rows from HTML table and init each row
this.init_identitieslist = function(identities_list)
{
if (identities_list && identities_list.tBodies[0])
{
this.identity_rows = new Array();
var row;
for(var r=0; r<identities_list.tBodies[0].childNodes.length; r++)
{
row = identities_list.tBodies[0].childNodes[r];
this.init_table_row(row, 'identity_rows');
}
}
// alias to common rows array
this.list_rows = this.identity_rows;
if (this.env.iid)
this.highlight_row(this.env.iid);
};
/*********************************************************/
/********* client command interface *********/
/*********************************************************/
// execute a specific command on the web client
this.command = function(command, props, obj)
{
if (obj && obj.blur)
obj.blur();
if (this.busy)
return false;
// command not supported or allowed
if (!this.commands[command])
{
// pass command to parent window
if (this.env.framed && parent.rcmail && parent.rcmail.command)
parent.rcmail.command(command, props);
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)
{
case 'login':
if (this.gui_objects.loginform)
this.gui_objects.loginform.submit();
break;
case 'logout':
location.href = this.env.comm_path+'&_action=logout';
break;
// commands to switch task
case 'mail':
case 'addressbook':
case 'settings':
this.switch_task(command);
break;
// misc list commands
case 'list':
if (this.task=='mail')
{
if (this.env.search_request<0 || (this.env.search_request && props != this.env.mailbox))
this.reset_qsearch();
// Reset message list header, unless returning from compose/read/etc
if (this.env.mailbox != props && this.message_rows)
this.clear_message_list_header();
this.list_mailbox(props);
}
else if (this.task=='addressbook')
this.list_contacts();
break;
case 'sort':
// get the type of sorting
var a_sort = props.split('_');
var sort_col = a_sort[0];
var sort_order = a_sort[1] ? a_sort[1].toUpperCase() : null;
var header;
// no sort order specified: toggle
if (sort_order==null)
{
if (this.env.sort_col==sort_col)
sort_order = this.env.sort_order=='ASC' ? 'DESC' : 'ASC';
else
sort_order = this.env.sort_order;
}
if (this.env.sort_col==sort_col && this.env.sort_order==sort_order)
break;
// set table header class
if (header = document.getElementById('rcmHead'+this.env.sort_col))
this.set_classname(header, 'sorted'+(this.env.sort_order.toUpperCase()), false);
if (header = document.getElementById('rcmHead'+sort_col))
this.set_classname(header, 'sorted'+sort_order, true);
// save new sort properties
this.env.sort_col = sort_col;
this.env.sort_order = sort_order;
// reload message list
this.list_mailbox('', '', sort_col+'_'+sort_order);
break;
case 'nextpage':
this.list_page('next');
break;
case 'previouspage':
this.list_page('prev');
break;
case 'expunge':
if (this.env.messagecount)
this.expunge_mailbox(this.env.mailbox);
break;
case 'purge':
case 'empty-mailbox':
if (this.env.messagecount)
this.purge_mailbox(this.env.mailbox);
break;
// common commands used in multiple tasks
case 'show':
if (this.task=='mail')
{
var uid = this.get_single_uid();
if (uid && (!this.env.uid || uid != this.env.uid))
{
if (this.env.mailbox==this.env.drafts_mailbox)
{
this.set_busy(true);
location.href = this.env.comm_path+'&_action=compose&_draft_uid='+uid+'&_mbox='+escape(this.env.mailbox);
}
else
{
this.show_message(uid);
}
}
}
else if (this.task=='addressbook')
{
var cid = props ? props : this.get_single_cid();
if (cid && !(this.env.action=='show' && cid==this.env.cid))
this.load_contact(cid, 'show');
}
break;
case 'add':
if (this.task=='addressbook')
if (!window.frames[this.env.contentframe].rcmail)
this.load_contact(0, 'add');
else
{
if (window.frames[this.env.contentframe].rcmail.selection.length)
this.add_ldap_contacts();
else
this.load_contact(0, 'add');
}
else if (this.task=='settings')
{
this.clear_selection();
this.load_identity(0, 'add-identity');
}
break;
case 'edit':
var cid;
if (this.task=='addressbook' && (cid = this.get_single_cid()))
this.load_contact(cid, 'edit');
else if (this.task=='settings' && props)
this.load_identity(props, 'edit-identity');
break;
case 'save-identity':
case 'save':
if (this.gui_objects.editform)
{
var input_pagesize = rcube_find_object('_pagesize');
var input_name = rcube_find_object('_name');
var input_email = rcube_find_object('_email');
// user prefs
if (input_pagesize && isNaN(input_pagesize.value))
{
alert(this.get_label('nopagesizewarning'));
input_pagesize.focus();
break;
}
// contacts/identities
else
{
if (input_name && input_name.value == '')
{
alert(this.get_label('nonamewarning'));
input_name.focus();
break;
}
else if (input_email && !rcube_check_email(input_email.value))
{
alert(this.get_label('noemailwarning'));
input_email.focus();
break;
}
}
this.gui_objects.editform.submit();
}
break;
case 'delete':
// mail task
if (this.task=='mail')
this.delete_messages();
// addressbook task
else if (this.task=='addressbook')
this.delete_contacts();
// user settings task
else if (this.task=='settings')
this.delete_identity();
break;
// mail task commands
case 'move':
case 'moveto':
this.move_messages(props);
break;
case 'toggle_status':
if (props && !props._row)
break;
var uid;
var flag = 'read';
if (props._row.uid)
{
uid = props._row.uid;
this.dont_select = true;
// toggle read/unread
if (this.message_rows[uid].deleted) {
flag = 'undelete';
} else if (!this.message_rows[uid].unread)
flag = 'unread';
}
this.mark_message(flag, uid);
break;
case 'load-images':
if (this.env.uid)
this.show_message(this.env.uid, true);
break;
case 'load-attachment':
var url = this.env.comm_path+'&_action=get&_mbox='+this.env.mailbox+'&_uid='+this.env.uid+'&_part='+props.part;
// open attachment in frame if it's of a supported mimetype
if (this.env.uid && props.mimetype && find_in_array(props.mimetype, this.mimetypes)>=0)
{
this.attachment_win = window.open(url+'&_frame=1', 'rcubemailattachment');
if (this.attachment_win)
{
setTimeout(this.ref+'.attachment_win.focus()', 10);
break;
}
}
location.href = url;
break;
case 'select-all':
this.select_all(props);
break;
case 'select-none':
this.clear_selection();
break;
case 'nextmessage':
if (this.env.next_uid)
this.show_message(this.env.next_uid);
//location.href = this.env.comm_path+'&_action=show&_uid='+this.env.next_uid+'&_mbox='+this.env.mailbox;
break;
case 'previousmessage':
if (this.env.prev_uid)
this.show_message(this.env.prev_uid);
//location.href = this.env.comm_path+'&_action=show&_uid='+this.env.prev_uid+'&_mbox='+this.env.mailbox;
break;
case 'checkmail':
this.check_for_recent();
break;
case 'compose':
var url = this.env.comm_path+'&_action=compose';
if (this.task=='mail' && this.env.mailbox==this.env.drafts_mailbox)
{
var uid = this.get_single_uid();
url += '&_draft_uid='+uid+'&_mbox='+escape(this.env.mailbox);
}
// modify url if we're in addressbook
else if (this.task=='addressbook')
{
url = this.get_task_url('mail', url);
var a_cids = new Array();
// use contact_id passed as command parameter
if (props)
a_cids[a_cids.length] = props;
// get selected contacts
else
{
if (!window.frames[this.env.contentframe].rcmail.selection.length)
{
for (var n=0; n<this.selection.length; n++)
a_cids[a_cids.length] = this.selection[n];
}
else
{
var frameRcmail = window.frames[this.env.contentframe].rcmail;
// get the email address(es)
for (var n=0; n<frameRcmail.selection.length; n++)
a_cids[a_cids.length] = frameRcmail.ldap_contact_rows[frameRcmail.selection[n]].obj.cells[1].innerHTML;
}
}
if (a_cids.length)
url += '&_to='+a_cids.join(',');
else
break;
}
else if (props)
url += '&_to='+props;
// don't know if this is necessary...
url = url.replace(/&_framed=1/, "");
this.set_busy(true);
// need parent in case we are coming from the contact frame
if (this.env.framed)
parent.location.href = url;
else
location.href = url;
break;
case 'spellcheck':
if (this.env.spellcheck && this.env.spellcheck.spellCheck)
this.env.spellcheck.spellCheck(this.env.spellcheck.check_link);
break;
case 'savedraft':
if (!this.gui_objects.messageform)
break;
// if saving Drafts is disabled in main.inc.php
if (!this.env.drafts_mailbox)
break;
this.set_busy(true, 'savingmessage');
var form = this.gui_objects.messageform;
form.submit();
break;
case 'send':
if (!this.gui_objects.messageform)
break;
if (!this.check_compose_input())
break;
// all checks passed, send message
this.set_busy(true, 'sendingmessage');
var form = this.gui_objects.messageform;
form._draft.value='';
form.submit();
break;
case 'add-attachment':
this.show_attachment_form(true);
case 'send-attachment':
this.upload_file(props)
break;
case 'remove-attachment':
this.remove_attachment(props);
break;
case 'reply-all':
case 'reply':
var uid;
if (uid = this.get_single_uid())
{
this.set_busy(true);
location.href = this.env.comm_path+'&_action=compose&_reply_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : '');
}
break;
case 'forward':
var uid;
if (uid = this.get_single_uid())
{
this.set_busy(true);
location.href = this.env.comm_path+'&_action=compose&_forward_uid='+uid+'&_mbox='+escape(this.env.mailbox);
}
break;
case 'print':
var uid;
if (uid = this.get_single_uid())
{
this.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''));
if (this.printwin)
setTimeout(this.ref+'.printwin.focus()', 20);
}
break;
case 'viewsource':
var uid;
if (uid = this.get_single_uid())
{
this.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+escape(this.env.mailbox));
if (this.sourcewin)
setTimeout(this.ref+'.sourcewin.focus()', 20);
}
break;
case 'add-contact':
this.add_contact(props);
break;
// mail quicksearch
case 'search':
if (!props && this.gui_objects.qsearchbox)
props = this.gui_objects.qsearchbox.value;
if (props)
this.qsearch(escape(props), this.env.mailbox);
break;
// reset quicksearch
case 'reset-search':
var s = this.env.search_request;
this.reset_qsearch();
if (s)
this.list_mailbox(this.env.mailbox);
break;
// ldap search
case 'ldappublicsearch':
if (this.gui_objects.ldappublicsearchform)
this.gui_objects.ldappublicsearchform.submit();
else
this.ldappublicsearch(command);
break;
// user settings commands
case 'preferences':
location.href = this.env.comm_path;
break;
case 'identities':
location.href = this.env.comm_path+'&_action=identities';
break;
case 'delete-identity':
this.delete_identity();
case 'folders':
location.href = this.env.comm_path+'&_action=folders';
break;
case 'subscribe':
this.subscribe_folder(props);
break;
case 'unsubscribe':
this.unsubscribe_folder(props);
break;
case 'create-folder':
this.create_folder(props);
break;
case 'rename-folder':
this.rename_folder(props);
break;
case 'delete-folder':
if (confirm(this.get_label('deletefolderconfirm')))
this.delete_folder(props);
break;
}
return obj ? false : true;
};
// set command enabled or disabled
this.enable_command = function()
{
var args = arguments;
if(!args.length) return -1;
var command;
var enable = args[args.length-1];
for(var n=0; n<args.length-1; n++)
{
command = args[n];
this.commands[command] = enable;
this.set_button(command, (enable ? 'act' : 'pas'));
}
return true;
};
// lock/unlock interface
this.set_busy = function(a, message)
{
if (a && message)
{
var msg = this.get_label(message);
if (msg==message)
msg = 'Loading...';
this.display_message(msg, 'loading', true);
}
else if (!a && this.busy)
this.hide_message();
this.busy = a;
//document.body.style.cursor = a ? 'wait' : 'default';
if (this.gui_objects.editform)
this.lock_form(this.gui_objects.editform, a);
// clear pending timer
if (this.request_timer)
clearTimeout(this.request_timer);
// set timer for requests
if (a && this.request_timeout)
this.request_timer = setTimeout(this.ref+'.request_timed_out()', this.request_timeout);
};
// return a localized string
this.get_label = function(name)
{
if (this.labels[name])
return this.labels[name];
else
return name;
};
// switch to another application task
this.switch_task = function(task)
{
if (this.task===task && task!='mail')
return;
var url = this.get_task_url(task);
if (task=='mail')
url += '&_mbox=INBOX';
this.set_busy(true);
location.href = url;
};
this.get_task_url = function(task, url)
{
if (!url)
url = this.env.comm_path;
return url.replace(/_task=[a-z]+/, '_task='+task);
};
// called when a request timed out
this.request_timed_out = function()
{
this.set_busy(false);
this.display_message('Request timed out!', 'error');
};
/*********************************************************/
/********* event handling methods *********/
/*********************************************************/
// onmouseup handler for mailboxlist item
this.mbox_mouse_up = function(mbox)
{
if (this.drag_active)
this.command('moveto', mbox);
else
this.command('list', mbox);
return false;
};
// onmousedown-handler of message list row
this.drag_row = function(e, id)
{
this.in_selection_before = this.in_selection(id) ? id : false;
// don't do anything (another action processed before)
if (this.dont_select)
return false;
// selects currently unselected row
if (!this.in_selection_before && !this.list_rows[id].clicked)
{
var mod_key = this.get_modifier(e);
this.select_row(id,mod_key,false);
}
if (this.selection.length)
{
this.drag_start = true;
document.onmousemove = function(e){ return rcube_webmail_client.drag_mouse_move(e); };
document.onmouseup = function(e){ return rcube_webmail_client.drag_mouse_up(e); };
}
return false;
};
// onmouseup-handler of message list row
this.click_row = function(e, id)
{
var mod_key = this.get_modifier(e);
// don't do anything (another action processed before)
if (this.dont_select)
{
this.dont_select = false;
return false;
}
// unselects currently selected row
if (!this.drag_active && this.in_selection_before==id && !this.list_rows[id].clicked)
this.select_row(id,mod_key,false);
this.drag_start = false;
this.in_selection_before = false;
// row was double clicked
if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked && this.in_selection(id))
{
if (this.env.mailbox==this.env.drafts_mailbox)
{
this.set_busy(true);
location.href = this.env.comm_path+'&_action=compose&_draft_uid='+id+'&_mbox='+escape(this.env.mailbox);
}
else
{
this.show_message(id);
}
return false;
}
else if (this.task=='addressbook')
{
if (this.contact_rows && this.selection.length==1)
{
this.load_contact(this.selection[0], 'show', true);
// change the text for the add contact button
var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
for (i = 0; i < links.length; i++)
{
var onclickstring = new String(links[i].onclick);
if (onclickstring.search('\"add\"') != -1)
links[i].title = this.env.newcontact;
}
}
else if (this.contact_rows && this.contact_rows[id].clicked)
{
this.load_contact(id, 'show');
return false;
}
else if (this.ldap_contact_rows && !this.ldap_contact_rows[id].clicked)
{
// clear selection
parent.rcmail.clear_selection();
// disable delete
parent.rcmail.set_button('delete', 'pas');
// change the text for the add contact button
var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
for (i = 0; i < links.length; i++)
{
var onclickstring = new String(links[i].onclick);
if (onclickstring.search('\"add\"') != -1)
links[i].title = this.env.addcontact;
}
}
// handle double click event
else if (this.ldap_contact_rows && this.selection.length==1 && this.ldap_contact_rows[id].clicked)
this.command('compose', this.ldap_contact_rows[id].obj.cells[1].innerHTML);
else if (this.env.contentframe)
{
var elm = document.getElementById(this.env.contentframe);
elm.style.visibility = 'hidden';
}
}
else if (this.task=='settings')
{
if (this.selection.length==1)
this.command('edit', this.selection[0]);
}
this.list_rows[id].clicked = true;
setTimeout(this.ref+'.list_rows['+id+'].clicked=false;', this.dblclick_time);
return false;
};
/*********************************************************/
/********* (message) list functionality *********/
/*********************************************************/
// get next and previous rows that are not hidden
this.get_next_row = function(){
if (!this.list_rows) return false;
var last_selected_row = this.list_rows[this.last_selected];
var new_row = last_selected_row.obj.nextSibling;
while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) {
new_row = new_row.nextSibling;
}
return new_row;
}
this.get_prev_row = function(){
if (!this.list_rows) return false;
var last_selected_row = this.list_rows[this.last_selected];
var new_row = last_selected_row.obj.previousSibling;
while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) {
new_row = new_row.previousSibling;
}
return new_row;
}
// highlight/unhighlight a row
this.highlight_row = function(id, multiple)
{
var selected = false
if (this.list_rows[id] && !multiple)
{
this.clear_selection();
this.selection[0] = id;
this.list_rows[id].obj.className += ' selected';
selected = true;
}
else if (this.list_rows[id])
{
if (!this.in_selection(id)) // select row
{
this.selection[this.selection.length] = id;
this.set_classname(this.list_rows[id].obj, 'selected', true);
}
else // unselect row
{
var p = find_in_array(id, this.selection);
var a_pre = this.selection.slice(0, p);
var a_post = this.selection.slice(p+1, this.selection.length);
this.selection = a_pre.concat(a_post);
this.set_classname(this.list_rows[id].obj, 'selected', false);
this.set_classname(this.list_rows[id].obj, 'unfocused', false);
}
selected = (this.selection.length==1);
}
// enable/disable commands for message
if (this.task=='mail')
{
if (this.env.mailbox==this.env.drafts_mailbox)
{
this.enable_command('show', selected);
this.enable_command('delete', this.selection.length>0 ? true : false);
}
else
{
this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', selected);
this.enable_command('delete', 'moveto', this.selection.length>0 ? true : false);
}
}
else if (this.task=='addressbook')
{
this.enable_command('edit', /*'print',*/ selected);
this.enable_command('delete', 'compose', this.selection.length>0 ? true : false);
}
};
// selects or unselects the proper row depending on the modifier key pressed
this.select_row = function(id,mod_key,with_mouse) {
if (!mod_key) {
this.shift_start = id;
this.highlight_row(id, false);
} else {
switch (mod_key) {
case SHIFT_KEY: {
this.shift_select(id,false);
break; }
case CONTROL_KEY: {
this.shift_start = id;
if (!with_mouse)
this.highlight_row(id, true);
break;
}
case CONTROL_SHIFT_KEY: {
this.shift_select(id,true);
break;
}
default: {
this.highlight_row(id, false);
break;
}
}
}
if (this.last_selected != 0) { this.set_classname(this.list_rows[this.last_selected].obj, 'focused', false);}
this.last_selected = id;
this.set_classname(this.list_rows[id].obj, 'focused', true);
};
this.shift_select = function(id, control) {
var from_rowIndex = this.list_rows[this.shift_start].obj.rowIndex;
var to_rowIndex = this.list_rows[id].obj.rowIndex;
var i = ((from_rowIndex < to_rowIndex)? from_rowIndex : to_rowIndex);
var j = ((from_rowIndex > to_rowIndex)? from_rowIndex : to_rowIndex);
// iterate through the entire message list
for (var n in this.list_rows) {
if ((this.list_rows[n].obj.rowIndex >= i) && (this.list_rows[n].obj.rowIndex <= j)) {
if (!this.in_selection(n))
this.highlight_row(n, true);
} else {
if (this.in_selection(n) && !control)
this.highlight_row(n, true);
}
}
};
this.clear_selection = function()
{
for(var n=0; n<this.selection.length; n++)
if (this.list_rows[this.selection[n]]) {
this.set_classname(this.list_rows[this.selection[n]].obj, 'selected', false);
this.set_classname(this.list_rows[this.selection[n]].obj, 'unfocused', false);
}
this.selection = new Array();
};
// check if given id is part of the current selection
this.in_selection = function(id)
{
for(var n in this.selection)
if (this.selection[n]==id)
return true;
return false;
};
// select each row in list
this.select_all = function(filter)
{
if (!this.list_rows || !this.list_rows.length)
return false;
// reset selection first
this.clear_selection();
for (var n in this.list_rows) {
if (!filter || this.list_rows[n][filter]==true)
+ this.last_selected = n;
this.highlight_row(n, true);
}
return true;
};
// when user doble-clicks on a row
this.show_message = function(id, safe)
{
var add_url = '';
var target = window;
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
target = window.frames[this.env.contentframe];
add_url = '&_framed=1';
}
if (safe)
add_url = '&_safe=1';
if (id)
{
this.set_busy(true, 'loading');
target.location.href = this.env.comm_path+'&_action=show&_uid='+id+'&_mbox='+escape(this.env.mailbox)+add_url;
}
};
// list a specific page
this.list_page = function(page)
{
if (page=='next')
page = this.env.current_page+1;
if (page=='prev' && this.env.current_page>1)
page = this.env.current_page-1;
if (page > 0 && page <= this.env.pagecount)
{
this.env.current_page = page;
if (this.task=='mail')
this.list_mailbox(this.env.mailbox, page);
else if (this.task=='addressbook')
this.list_contacts(page);
}
};
// list messages of a specific mailbox
this.list_mailbox = function(mbox, page, sort)
{
this.last_selected = 0;
var add_url = '';
var target = window;
if (!mbox)
mbox = this.env.mailbox;
// add sort to url if set
if (sort)
add_url += '&_sort=' + sort;
// set page=1 if changeing to another mailbox
if (!page && mbox != this.env.mailbox)
{
page = 1;
add_url += '&_refresh=1';
this.env.current_page = page;
this.clear_selection();
}
// also send search request to get the right messages
if (this.env.search_request)
add_url += '&_search='+this.env.search_request;
if (this.env.mailbox!=mbox)
this.select_mailbox(mbox);
// load message list remotely
if (this.gui_objects.messagelist)
{
this.list_mailbox_remote(mbox, page, add_url);
return;
}
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
target = window.frames[this.env.contentframe];
add_url += '&_framed=1';
}
// load message list to target frame/window
if (mbox)
{
this.set_busy(true, 'loading');
target.location.href = this.env.comm_path+'&_mbox='+escape(mbox)+(page ? '&_page='+page : '')+add_url;
}
};
// send remote request to load message list
this.list_mailbox_remote = function(mbox, page, add_url)
{
// 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]);
table.removeChild(table.tBodies[1]);
this.message_rows = new Array();
this.list_rows = this.message_rows;
};
this.clear_message_list_header = function()
{
var table = this.gui_objects.messagelist;
var colgroup = document.createElement('COLGROUP');
table.removeChild(table.colgroup);
table.insertBefore(colgroup, table.thead);
var thead = document.createElement('THEAD');
table.removeChild(table.thead);
table.insertBefore(thead, table.tBodies[0]);
};
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);
this.http_request('expunge', url+add_url, lock);
};
this.purge_mailbox = function(mbox)
{
var lock = false;
var add_url = '';
if (!confirm(this.get_label('purgefolderconfirm')))
return false;
// 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);
this.http_request('purge', url+add_url, lock);
return true;
};
// move selected messages to the specified mailbox
this.move_messages = function(mbox)
{
// exit if no mailbox specified or if selection is empty
if (!mbox || !(this.selection.length || this.env.uid) || mbox==this.env.mailbox)
return;
var a_uids = new Array();
if (this.env.uid)
a_uids[a_uids.length] = this.env.uid;
else
{
var id;
for (var n=0; n<this.selection.length; n++)
{
id = this.selection[n];
a_uids[a_uids.length] = id;
// 'remove' message row from list (just hide it)
if (this.message_rows[id].obj)
this.message_rows[id].obj.style.display = 'none';
}
next_row = this.get_next_row();
prev_row = this.get_prev_row();
new_row = (next_row) ? next_row : prev_row;
if (new_row) this.select_row(new_row.uid,false,false);
}
var lock = false;
// show wait message
if (this.env.action=='show')
{
lock = true;
this.set_busy(true, 'movingmessage');
}
// send request to server
this.http_request('moveto', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_target_mbox='+escape(mbox)+'&_from='+(this.env.action ? this.env.action : ''), lock);
};
this.permanently_remove_messages = function() {
// exit if no mailbox specified or if selection is empty
if (!(this.selection.length || this.env.uid))
return;
var a_uids = new Array();
if (this.env.uid)
a_uids[a_uids.length] = this.env.uid;
else
{
var id;
for (var n=0; n<this.selection.length; n++)
{
id = this.selection[n];
a_uids[a_uids.length] = id;
// 'remove' message row from list (just hide it)
if (this.message_rows[id].obj)
this.message_rows[id].obj.style.display = 'none';
}
}
next_row = this.get_next_row();
prev_row = this.get_prev_row();
new_row = (next_row) ? next_row : prev_row;
if (new_row) this.select_row(new_row.uid,false,false);
// send request to server
this.http_request('delete', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_from='+(this.env.action ? this.env.action : ''));
}
// delete selected messages from the current mailbox
this.delete_messages = function()
{
// exit if no mailbox specified or if selection is empty
if (!(this.selection.length || this.env.uid))
return;
// if there is a trash mailbox defined and we're not currently in it:
if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase()!=String(this.env.trash_mailbox).toLowerCase())
this.move_messages(this.env.trash_mailbox);
// if there is a trash mailbox defined but we *are* in it:
else if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase() == String(this.env.trash_mailbox).toLowerCase())
this.permanently_remove_messages();
// if there isn't a defined trash mailbox and the config is set to flag for deletion
else if (!this.env.trash_mailbox && this.env.flag_for_deletion) {
flag = 'delete';
this.mark_message(flag);
if(this.env.action=="show"){
this.command('nextmessage','',this);
} else if (this.selection.length == 1) {
next_row = this.get_next_row();
prev_row = this.get_prev_row();
new_row = (next_row) ? next_row : prev_row;
if (new_row) this.select_row(new_row.uid,false,false);
}
// if there isn't a defined trash mailbox and the config is set NOT to flag for deletion
}else if (!this.env.trash_mailbox && !this.env.flag_for_deletion) {
this.permanently_remove_messages();
}
return;
};
// set a specific flag to one or more messages
this.mark_message = function(flag, uid)
{
var a_uids = new Array();
if (uid)
a_uids[0] = uid;
else if (this.env.uid)
a_uids[0] = this.env.uid;
else
{
var id;
for (var n=0; n<this.selection.length; n++)
{
id = this.selection[n];
a_uids[a_uids.length] = id;
}
}
switch (flag) {
case 'read':
case 'unread':
this.toggle_read_status(flag,a_uids);
break;
case 'delete':
case 'undelete':
this.toggle_delete_status(a_uids);
break;
}
};
// set class to read/unread
this.toggle_read_status = function(flag, a_uids) {
// mark all message rows as read/unread
var icn_src;
for (var i=0; i<a_uids.length; i++)
{
uid = a_uids[i];
if (this.message_rows[uid])
{
this.message_rows[uid].unread = (flag=='unread' ? true : false);
if (this.message_rows[uid].classname.indexOf('unread')<0 && this.message_rows[uid].unread)
{
this.message_rows[uid].classname += ' unread';
this.set_classname(this.message_rows[uid].obj, 'unread', true);
if (this.env.unreadicon)
icn_src = this.env.unreadicon;
}
else if (!this.message_rows[uid].unread)
{
this.message_rows[uid].classname = this.message_rows[uid].classname.replace(/\s*unread/, '');
this.set_classname(this.message_rows[uid].obj, 'unread', false);
if (this.message_rows[uid].replied && this.env.repliedicon)
icn_src = this.env.repliedicon;
else if (this.env.messageicon)
icn_src = this.env.messageicon;
}
if (this.message_rows[uid].icon && icn_src)
this.message_rows[uid].icon.src = icn_src;
}
}
this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
}
// mark all message rows as deleted/undeleted
this.toggle_delete_status = function(a_uids) {
if (this.env.read_when_deleted) {
this.toggle_read_status('read',a_uids);
}
// if deleting message from "view message" don't bother with delete icon
if (this.env.action == "show")
return false;
if (a_uids.length==1){
if(this.message_rows[a_uids[0]].classname.indexOf('deleted') < 0 ){
this.flag_as_deleted(a_uids)
} else {
this.flag_as_undeleted(a_uids)
}
return true;
}
var all_deleted = true;
for (var i=0; i<a_uids.length; i++) {
uid = a_uids[i];
if (this.message_rows[uid]) {
if (this.message_rows[uid].classname.indexOf('deleted')<0) {
all_deleted = false;
break;
}
}
}
if (all_deleted)
this.flag_as_undeleted(a_uids);
else
this.flag_as_deleted(a_uids);
return true;
}
this.flag_as_undeleted = function(a_uids){
// if deleting message from "view message" don't bother with delete icon
if (this.env.action == "show")
return false;
var icn_src;
for (var i=0; i<a_uids.length; i++) {
uid = a_uids[i];
if (this.message_rows[uid]) {
this.message_rows[uid].deleted = false;
if (this.message_rows[uid].classname.indexOf('deleted') > 0) {
this.message_rows[uid].classname = this.message_rows[uid].classname.replace(/\s*deleted/, '');
this.set_classname(this.message_rows[uid].obj, 'deleted', false);
}
if (this.message_rows[uid].unread && this.env.unreadicon)
icn_src = this.env.unreadicon;
else if (this.message_rows[uid].replied && this.env.repliedicon)
icn_src = this.env.repliedicon;
else if (this.env.messageicon)
icn_src = this.env.messageicon;
if (this.message_rows[uid].icon && icn_src)
this.message_rows[uid].icon.src = icn_src;
}
}
this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag=undelete');
return true;
}
this.flag_as_deleted = function(a_uids) {
// if deleting message from "view message" don't bother with delete icon
if (this.env.action == "show")
return false;
for (var i=0; i<a_uids.length; i++) {
uid = a_uids[i];
if (this.message_rows[uid]) {
this.message_rows[uid].deleted = true;
if (this.message_rows[uid].classname.indexOf('deleted')<0) {
this.message_rows[uid].classname += ' deleted';
this.set_classname(this.message_rows[uid].obj, 'deleted', true);
}
if (this.message_rows[uid].icon && this.env.deletedicon)
this.message_rows[uid].icon.src = this.env.deletedicon;
}
}
this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag=delete');
return true;
}
/*********************************************************/
/********* message compose methods *********/
/*********************************************************/
// checks the input fields before sending a message
this.check_compose_input = function()
{
// check input fields
var input_to = rcube_find_object('_to');
var input_subject = rcube_find_object('_subject');
var input_message = rcube_find_object('_message');
// check for empty recipient
if (input_to && !rcube_check_email(input_to.value, true))
{
alert(this.get_label('norecipientwarning'));
input_to.focus();
return false;
}
// display localized warning for missing subject
if (input_subject && input_subject.value == '')
{
var subject = prompt(this.get_label('nosubjectwarning'), this.get_label('nosubject'));
// user hit cancel, so don't send
if (!subject && subject !== '')
{
input_subject.focus();
return false;
}
else
{
input_subject.value = subject ? subject : this.get_label('nosubject');
}
}
// check for empty body
if (input_message.value=='')
{
if (!confirm(this.get_label('nobodywarning')))
{
input_message.focus();
return false;
}
}
return true;
};
this.compose_field_hash = function()
{
// check input fields
var input_to = rcube_find_object('_to');
var input_cc = rcube_find_object('_to');
var input_bcc = rcube_find_object('_to');
var input_subject = rcube_find_object('_subject');
var input_message = rcube_find_object('_message');
var str = '';
if (input_to && input_to.value)
str += input_to.value+':';
if (input_cc && input_cc.value)
str += input_cc.value+':';
if (input_bcc && input_bcc.value)
str += input_bcc.value+':';
if (input_subject && input_subject.value)
str += input_subject.value+':';
if (input_message && input_message.value)
str += input_message.value;
return str;
};
this.change_identity = function(obj)
{
if (!obj || !obj.options)
return false;
var id = obj.options[obj.selectedIndex].value;
var input_message = rcube_find_object('_message');
var message = input_message ? input_message.value : '';
var sig, p;
if (!this.env.identity)
this.env.identity = id
// remove the 'old' signature
if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity])
{
sig = this.env.signatures[this.env.identity];
if (sig.indexOf('--')!=0)
sig = '--\n'+sig;
p = message.lastIndexOf(sig);
if (p>=0)
message = message.substring(0, p-1) + message.substring(p+sig.length, message.length);
}
// add the new signature string
if (this.env.signatures && this.env.signatures[id])
{
sig = this.env.signatures[id];
if (sig.indexOf('--')!=0)
sig = '--\n'+sig;
message += '\n'+sig;
}
if (input_message)
input_message.value = message;
this.env.identity = id;
return true;
};
this.show_attachment_form = function(a)
{
if (!this.gui_objects.uploadbox)
return false;
var elm, list;
if (elm = this.gui_objects.uploadbox)
{
if (a && (list = this.gui_objects.attachmentlist))
{
var pos = rcube_get_object_pos(list);
var left = pos.x;
var top = pos.y + list.offsetHeight + 10;
elm.style.top = top+'px';
elm.style.left = left+'px';
}
elm.style.visibility = a ? 'visible' : 'hidden';
}
// clear upload form
if (!a && this.gui_objects.attachmentform && this.gui_objects.attachmentform!=this.gui_objects.messageform)
this.gui_objects.attachmentform.reset();
return true;
};
// upload attachment file
this.upload_file = function(form)
{
if (!form)
return false;
// get file input fields
var send = false;
for (var n=0; n<form.elements.length; n++)
if (form.elements[n].type=='file' && form.elements[n].value)
{
send = true;
break;
}
// create hidden iframe and post upload form
if (send)
{
var ts = new Date().getTime();
var frame_name = 'rcmupload'+ts;
// have to do it this way for IE
// otherwise the form will be posted to a new window
if(document.all && !window.opera)
{
var html = '<iframe name="'+frame_name+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
document.body.insertAdjacentHTML('BeforeEnd',html);
}
else // for standards-compilant browsers
{
var frame = document.createElement('IFRAME');
frame.name = frame_name;
frame.width = 10;
frame.height = 10;
frame.style.visibility = 'hidden';
document.body.appendChild(frame);
}
form.target = frame_name;
form.action = this.env.comm_path+'&_action=upload';
form.setAttribute('enctype', 'multipart/form-data');
form.submit();
}
// set reference to the form object
this.gui_objects.attachmentform = form;
return true;
};
// add file name to attachment list
// called from upload page
this.add2attachment_list = function(name,content)
{
if (!this.gui_objects.attachmentlist)
return false;
var li = document.createElement('LI');
li.id = name;
li.innerHTML = content;
this.gui_objects.attachmentlist.appendChild(li);
return true;
};
this.remove_from_attachment_list = function(name)
{
if (!this.gui_objects.attachmentlist)
return false;
var list = this.gui_objects.attachmentlist.getElementsByTagName("li");
for (i=0;i<list.length;i++)
if (list[i].id == name)
this.gui_objects.attachmentlist.removeChild(list[i]);
}
this.remove_attachment = function(name)
{
if (name)
this.http_request('remove-attachment', '_filename='+escape(name));
return true;
}
// send remote request to add a new contact
this.add_contact = function(value)
{
if (value)
this.http_request('addcontact', '_address='+value);
return true;
};
// send remote request to search mail
this.qsearch = function(value, mbox)
{
if (value && mbox)
{
this.clear_message_list();
this.set_busy(true, 'searching');
this.http_request('search', '_search='+value+'&_mbox='+mbox, true);
}
return true;
};
// reset quick-search form
this.reset_qsearch = function()
{
if (this.gui_objects.qsearchbox)
this.gui_objects.qsearchbox.value = '';
this.env.search_request = null;
return true;
};
/*********************************************************/
/********* keyboard live-search methods *********/
/*********************************************************/
// handler for keyboard events on address-fields
this.ksearch_keypress = function(e, obj)
{
if (typeof(this.env.contacts)!='object' || !this.env.contacts.length)
return true;
if (this.ksearch_timer)
clearTimeout(this.ksearch_timer);
if (!e)
e = window.event;
var highlight;
var key = e.keyCode ? e.keyCode : e.which;
switch (key)
{
case 38: // key up
case 40: // key down
if (!this.ksearch_pane)
break;
var dir = key==38 ? 1 : 0;
var next;
highlight = document.getElementById('rcmksearchSelected');
if (!highlight)
highlight = this.ksearch_pane.ul.firstChild;
if (highlight && (next = dir ? highlight.previousSibling : highlight.nextSibling))
{
highlight.removeAttribute('id');
//highlight.removeAttribute('class');
this.set_classname(highlight, 'selected', false);
this.set_classname(highlight, 'unfocused', false);
}
if (next)
{
next.setAttribute('id', 'rcmksearchSelected');
this.set_classname(next, 'selected', true);
this.ksearch_selected = next._rcm_id;
}
if (e.preventDefault)
e.preventDefault();
return false;
case 9: // tab
if(e.shiftKey)
break;
case 13: // enter
if (this.ksearch_selected===null || !this.ksearch_input || !this.ksearch_value)
break;
// get cursor pos
var inp_value = this.ksearch_input.value.toLowerCase();
var cpos = this.get_caret_pos(this.ksearch_input);
var p = inp_value.lastIndexOf(this.ksearch_value, cpos);
// replace search string with full address
var pre = this.ksearch_input.value.substring(0, p);
var end = this.ksearch_input.value.substring(p+this.ksearch_value.length, this.ksearch_input.value.length);
var insert = this.env.contacts[this.ksearch_selected]+', ';
this.ksearch_input.value = pre + insert + end;
//this.ksearch_input.value = this.ksearch_input.value.substring(0, p)+insert;
// set caret to insert pos
cpos = p+insert.length;
if (this.ksearch_input.setSelectionRange)
this.ksearch_input.setSelectionRange(cpos, cpos);
// hide ksearch pane
this.ksearch_hide();
if (e.preventDefault)
e.preventDefault();
return false;
case 27: // escape
this.ksearch_hide();
break;
}
// start timer
this.ksearch_timer = setTimeout(this.ref+'.ksearch_get_results()', 200);
this.ksearch_input = obj;
return true;
};
// address search processor
this.ksearch_get_results = function()
{
var inp_value = this.ksearch_input ? this.ksearch_input.value : null;
if (inp_value===null)
return;
// get string from current cursor pos to last comma
var cpos = this.get_caret_pos(this.ksearch_input);
var p = inp_value.lastIndexOf(',', cpos-1);
var q = inp_value.substring(p+1, cpos);
// trim query string
q = q.replace(/(^\s+|\s+$)/g, '').toLowerCase();
if (!q.length || q==this.ksearch_value)
{
if (!q.length && this.ksearch_pane && this.ksearch_pane.visible)
this.ksearch_pane.show(0);
return;
}
this.ksearch_value = q;
// start searching the contact list
var a_results = new Array();
var a_result_ids = new Array();
var c=0;
for (var i=0; i<this.env.contacts.length; i++)
{
if (this.env.contacts[i].toLowerCase().indexOf(q)>=0)
{
a_results[c] = this.env.contacts[i];
a_result_ids[c++] = i;
if (c==15) // limit search results
break;
}
}
// display search results
if (c && a_results.length)
{
var p, ul, li;
// create results pane if not present
if (!this.ksearch_pane)
{
ul = document.createElement('UL');
this.ksearch_pane = new rcube_layer('rcmKSearchpane', {vis:0, zindex:30000});
this.ksearch_pane.elm.appendChild(ul);
this.ksearch_pane.ul = ul;
}
else
ul = this.ksearch_pane.ul;
// remove all search results
ul.innerHTML = '';
// add each result line to list
for (i=0; i<a_results.length; i++)
{
li = document.createElement('LI');
li.innerHTML = a_results[i].replace(/</, '&lt;').replace(/>/, '&gt;');
li._rcm_id = a_result_ids[i];
ul.appendChild(li);
}
// check if last selected item is still in result list
if (this.ksearch_selected!==null)
{
p = find_in_array(this.ksearch_selected, a_result_ids);
if (p>=0 && ul.childNodes)
{
ul.childNodes[p].setAttribute('id', 'rcmksearchSelected');
this.set_classname(ul.childNodes[p], 'selected', true);
}
else
this.ksearch_selected = null;
}
// if no item selected, select the first one
if (this.ksearch_selected===null)
{
ul.firstChild.setAttribute('id', 'rcmksearchSelected');
this.set_classname(ul.firstChild, 'selected', true);
this.ksearch_selected = a_result_ids[0];
}
// resize the containing layer to fit the list
//this.ksearch_pane.resize(ul.offsetWidth, ul.offsetHeight);
// move the results pane right under the input box and make it visible
var pos = rcube_get_object_pos(this.ksearch_input);
this.ksearch_pane.move(pos.x, pos.y+this.ksearch_input.offsetHeight);
this.ksearch_pane.show(1);
}
// hide results pane
else
this.ksearch_hide();
};
this.ksearch_blur = function(e, obj)
{
if (this.ksearch_timer)
clearTimeout(this.ksearch_timer);
this.ksearch_value = '';
this.ksearch_input = null;
this.ksearch_hide();
};
this.ksearch_hide = function()
{
this.ksearch_selected = null;
if (this.ksearch_pane)
this.ksearch_pane.show(0);
};
/*********************************************************/
/********* address book methods *********/
/*********************************************************/
this.list_contacts = function(page)
{
var add_url = '';
var target = window;
if (page && this.current_page==page)
return false;
// load contacts remotely
if (this.gui_objects.contactslist)
{
this.list_contacts_remote(page);
return;
}
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
target = window.frames[this.env.contentframe];
add_url = '&_framed=1';
}
this.set_busy(true, 'loading');
location.href = this.env.comm_path+(page ? '&_page='+page : '')+add_url;
};
// send remote request to load contacts list
this.list_contacts_remote = function(page)
{
// clear list
var table = this.gui_objects.contactslist;
var tbody = document.createElement('TBODY');
table.insertBefore(tbody, table.tBodies[0]);
table.tBodies[1].style.display = 'none';
this.contact_rows = new Array();
this.list_rows = this.contact_rows;
// send request to server
var url = page ? '&_page='+page : '';
this.set_busy(true, 'loading');
this.http_request('list', url, true);
};
// load contact record
this.load_contact = function(cid, action, framed)
{
var add_url = '';
var target = window;
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
add_url = '&_framed=1';
target = window.frames[this.env.contentframe];
document.getElementById(this.env.contentframe).style.visibility = 'inherit';
}
else if (framed)
return false;
//if (this.env.framed && add_url=='')
// add_url = '&_framed=1';
if (action && (cid || action=='add'))
{
this.set_busy(true);
target.location.href = this.env.comm_path+'&_action='+action+'&_cid='+cid+add_url;
}
return true;
};
this.delete_contacts = function()
{
// exit if no mailbox specified or if selection is empty
if (!(this.selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm')))
return;
var a_cids = new Array();
if (this.env.cid)
a_cids[a_cids.length] = this.env.cid;
else
{
var id;
for (var n=0; n<this.selection.length; n++)
{
id = this.selection[n];
a_cids[a_cids.length] = id;
// 'remove' row from list (just hide it)
if (this.contact_rows[id].obj)
this.contact_rows[id].obj.style.display = 'none';
}
// hide content frame if we delete the currently displayed contact
if (this.selection.length==1 && this.env.contentframe)
{
var elm = document.getElementById(this.env.contentframe);
elm.style.visibility = 'hidden';
}
}
// send request to server
this.http_request('delete', '_cid='+a_cids.join(',')+'&_from='+(this.env.action ? this.env.action : ''));
return true;
};
// update a contact record in the list
this.update_contact_row = function(cid, cols_arr)
{
if (!this.contact_rows[cid] || !this.contact_rows[cid].obj)
return false;
var row = this.contact_rows[cid].obj;
for (var c=0; c<cols_arr.length; c++){
if (row.cells[c])
row.cells[c].innerHTML = cols_arr[c];
}
return true;
};
// load ldap search form
this.ldappublicsearch = function(action)
{
var add_url = '';
var target = window;
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
add_url = '&_framed=1';
target = window.frames[this.env.contentframe];
document.getElementById(this.env.contentframe).style.visibility = 'inherit';
}
else
return false;
if (action == 'ldappublicsearch')
target.location.href = this.env.comm_path+'&_action='+action+add_url;
return true;
};
// add ldap contacts to address book
this.add_ldap_contacts = function()
{
if (window.frames[this.env.contentframe].rcmail)
{
var frame = window.frames[this.env.contentframe];
// build the url
var url = '&_framed=1';
var emails = '&_emails=';
var names = '&_names=';
var end = '';
for (var n=0; n<frame.rcmail.selection.length; n++)
{
end = n < frame.rcmail.selection.length - 1 ? ',' : '';
emails += frame.rcmail.ldap_contact_rows[frame.rcmail.selection[n]].obj.cells[1].innerHTML + end;
names += frame.rcmail.ldap_contact_rows[frame.rcmail.selection[n]].obj.cells[0].innerHTML + end;
}
frame.location.href = this.env.comm_path + '&_action=save&_framed=1' + emails + names;
}
return false;
}
/*********************************************************/
/********* user settings methods *********/
/*********************************************************/
// load contact record
this.load_identity = function(id, action)
{
if (action=='edit-identity' && (!id || id==this.env.iid))
return false;
var add_url = '';
var target = window;
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
add_url = '&_framed=1';
target = window.frames[this.env.contentframe];
document.getElementById(this.env.contentframe).style.visibility = 'inherit';
}
if (action && (id || action=='add-identity'))
{
this.set_busy(true);
target.location.href = this.env.comm_path+'&_action='+action+'&_iid='+id+add_url;
}
return true;
};
this.delete_identity = function(id)
{
// exit if no mailbox specified or if selection is empty
if (!(this.selection.length || this.env.iid))
return;
if (!id)
id = this.env.iid ? this.env.iid : this.selection[0];
/*
// 'remove' row from list (just hide it)
if (this.identity_rows && this.identity_rows[id].obj)
{
this.clear_selection();
this.identity_rows[id].obj.style.display = 'none';
}
*/
// if (this.env.framed && id)
this.set_busy(true);
location.href = this.env.comm_path+'&_action=delete-identity&_iid='+id;
// else if (id)
// this.http_request('delete-identity', '_iid='+id);
return true;
};
this.create_folder = function(name)
{
var form;
if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
name = form.elements['_folder_name'].value;
if (name)
this.http_request('create-folder', '_name='+escape(name), true);
else if (form.elements['_folder_name'])
form.elements['_folder_name'].focus();
};
this.rename_folder = function(props)
{
var form;
if ((form = this.gui_objects.editform) && form.elements['_folder_oldname'] && form.elements['_folder_newname'])
{
oldname = form.elements['_folder_oldname'].value;
newname = form.elements['_folder_newname'].value;
}
if (oldname && newname)
this.http_request('rename-folder', '_folder_oldname='+escape(oldname)+'&_folder_newname='+escape(newname));
};
this.delete_folder = function(folder)
{
if (folder)
{
this.http_request('delete-folder', '_mboxes='+escape(folder));
}
};
this.remove_folder_row = function(folder)
{
for (var id in this.env.subscriptionrows)
if (this.env.subscriptionrows[id]==folder)
break;
var row;
if (id && (row = document.getElementById(id)))
row.style.display = 'none';
// remove folder from rename-folder list
var form;
if ((form = this.gui_objects.editform) && form.elements['_folder_oldname'])
{
for (var i=0;i<form.elements['_folder_oldname'].options.length;i++)
{
if (form.elements['_folder_oldname'].options[i].value == folder)
{
form.elements['_folder_oldname'].options[i] = null;
break;
}
}
}
form.elements['_folder_newname'].value='';
};
this.subscribe_folder = function(folder)
{
var form;
if ((form = this.gui_objects.editform) && form.elements['_unsubscribed'])
this.change_subscription('_unsubscribed', '_subscribed', 'subscribe');
else if (folder)
this.http_request('subscribe', '_mboxes='+escape(folder));
};
this.unsubscribe_folder = function(folder)
{
var form;
if ((form = this.gui_objects.editform) && form.elements['_subscribed'])
this.change_subscription('_subscribed', '_unsubscribed', 'unsubscribe');
else if (folder)
this.http_request('unsubscribe', '_mboxes='+escape(folder));
};
this.change_subscription = function(from, to, action)
{
var form;
if (form = this.gui_objects.editform)
{
var a_folders = new Array();
var list_from = form.elements[from];
for (var i=0; list_from && i<list_from.options.length; i++)
{
if (list_from.options[i] && list_from.options[i].selected)
{
a_folders[a_folders.length] = list_from.options[i].value;
list_from[i] = null;
i--;
}
}
// yes, we have some folders selected
if (a_folders.length)
{
var list_to = form.elements[to];
var index;
for (var n=0; n<a_folders.length; n++)
{
index = list_to.options.length;
list_to[index] = new Option(a_folders[n]);
}
this.http_request(action, '_mboxes='+escape(a_folders.join(',')));
}
}
};
// add a new folder to the subscription list by cloning a folder row
this.add_folder_row = function(name)
{
name = name.replace('\\',"");
if (!this.gui_objects.subscriptionlist)
return false;
var tbody = this.gui_objects.subscriptionlist.tBodies[0];
var id = tbody.childNodes.length+1;
if (!tbody.rows[0])
{
// Refresh to create the first table row
location.href = this.env.comm_path+'&_action=folders';
}
else
{
// clone a table row if there are existing rows
var row = this.clone_table_row(tbody.rows[0]);
row.id = 'rcmrow'+id;
tbody.appendChild(row);
}
// add to folder/row-ID map
this.env.subscriptionrows[row.id] = name;
// set folder name
row.cells[0].innerHTML = name;
if (row.cells[1].firstChild.tagName=='INPUT')
{
row.cells[1].firstChild.value = name;
row.cells[1].firstChild.checked = true;
}
if (row.cells[2].firstChild.tagName=='A')
row.cells[2].firstChild.onclick = new Function(this.ref+".command('delete-folder','"+name.replace('\'','\\\'')+"')");
var form;
if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
form.elements['_folder_name'].value = '';
// add new folder to rename-folder list
form.elements['_folder_oldname'].options[form.elements['_folder_oldname'].options.length] = new Option(name,name);
};
// duplicate a specific table row
this.clone_table_row = function(row)
{
var cell, td;
var new_row = document.createElement('TR');
for(var n=0; n<row.childNodes.length; n++)
{
cell = row.childNodes[n];
td = document.createElement('TD');
if (cell.className)
td.className = cell.className;
if (cell.align)
td.setAttribute('align', cell.align);
td.innerHTML = cell.innerHTML;
new_row.appendChild(td);
}
return new_row;
};
/*********************************************************/
/********* GUI functionality *********/
/*********************************************************/
// eable/disable buttons for page shifting
this.set_page_buttons = function()
{
this.enable_command('nextpage', (this.env.pagecount > this.env.current_page));
this.enable_command('previouspage', (this.env.current_page > 1));
}
// set button to a specific state
this.set_button = function(command, state)
{
var a_buttons = this.buttons[command];
var button, obj;
if(!a_buttons || !a_buttons.length)
return;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
obj = document.getElementById(button.id);
// get default/passive setting of the button
if (obj && button.type=='image' && !button.status)
button.pas = obj._original_src ? obj._original_src : obj.src;
else if (obj && !button.status)
button.pas = String(obj.className);
// set image according to button state
if (obj && button.type=='image' && button[state])
{
button.status = state;
obj.src = button[state];
}
// set class name according to button state
else if (obj && typeof(button[state])!='undefined')
{
button.status = state;
obj.className = button[state];
}
// disable/enable input buttons
if (obj && button.type=='input')
{
button.status = state;
obj.disabled = !state;
}
}
};
// mouse over button
this.button_over = function(command, id)
{
var a_buttons = this.buttons[command];
var button, img;
if(!a_buttons || !a_buttons.length)
return;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
if(button.id==id && button.status=='act')
{
img = document.getElementById(button.id);
if (img && button.over)
img.src = button.over;
}
}
};
// mouse down on button
this.button_sel = function(command, id)
{
var a_buttons = this.buttons[command];
var button, img;
if(!a_buttons || !a_buttons.length)
return;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
if(button.id==id && button.status=='act')
{
img = document.getElementById(button.id);
if (img && button.sel)
img.src = button.sel;
}
}
};
// mouse out of button
this.button_out = function(command, id)
{
var a_buttons = this.buttons[command];
var button, img;
if(!a_buttons || !a_buttons.length)
return;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
if(button.id==id && button.status=='act')
{
img = document.getElementById(button.id);
if (img && button.act)
img.src = button.act;
}
}
};
// set/unset a specific class name
this.set_classname = function(obj, classname, set)
{
var reg = new RegExp('\s*'+classname, 'i');
if (!set && obj.className.match(reg))
obj.className = obj.className.replace(reg, '');
else if (set && !obj.className.match(reg))
obj.className += ' '+classname;
};
// display a specific alttext
this.alttext = function(text)
{
};
// display a system message
this.display_message = function(msg, type, hold)
{
if (!this.loaded) // save message in order to display after page loaded
{
this.pending_message = new Array(msg, type);
return true;
}
if (!this.gui_objects.message)
return false;
if (this.message_timer)
clearTimeout(this.message_timer);
var cont = msg;
if (type)
cont = '<div class="'+type+'">'+cont+'</div>';
this.gui_objects.message._rcube = this;
this.gui_objects.message.innerHTML = cont;
this.gui_objects.message.style.display = 'block';
if (type!='loading')
this.gui_objects.message.onmousedown = function(){ this._rcube.hide_message(); return true; };
if (!hold)
this.message_timer = setTimeout(this.ref+'.hide_message()', this.message_time);
};
// make a message row disapear
this.hide_message = function()
{
if (this.gui_objects.message)
{
this.gui_objects.message.style.display = 'none';
this.gui_objects.message.onmousedown = null;
}
};
// mark a mailbox as selected and set environment variable
this.select_mailbox = function(mbox)
{
if (this.gui_objects.mailboxlist)
{
var item, reg, text_obj;
var s_current = this.env.mailbox.toLowerCase().replace(this.mbox_expression, '');
var s_mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
var s_current = this.env.mailbox.toLowerCase().replace(this.mbox_expression, '');
var current_li = document.getElementById('rcmbx'+s_current);
var mbox_li = document.getElementById('rcmbx'+s_mbox);
if (current_li) {
this.set_classname(current_li, 'selected', false);
this.set_classname(current_li, 'unfocused', false);
}
if (mbox_li)
this.set_classname(mbox_li, 'selected', true);
}
this.env.mailbox = mbox;
};
+ // for reordering column array, Konqueror workaround
+ this.set_message_coltypes = function(coltypes)
+ {
+ this.coltypes = coltypes;
+ }
// create a table row in the message list
this.add_message_row = function(uid, cols, flags, attachment, attop)
{
if (!this.gui_objects.messagelist || !this.gui_objects.messagelist.tBodies[0])
return false;
var tbody = this.gui_objects.messagelist.tBodies[0];
var rowcount = tbody.rows.length;
var even = rowcount%2;
this.env.messages[uid] = {deleted:flags.deleted?1:0,
replied:flags.replied?1:0,
unread:flags.unread?1:0};
var row = document.createElement('TR');
row.id = 'rcmrow'+uid;
row.className = 'message '+(even ? 'even' : 'odd')+(flags.unread ? ' unread' : '')+(flags.deleted ? ' deleted' : '');
if (this.in_selection(uid))
row.className += ' selected';
var icon = flags.deleted && this.env.deletedicon ? this.env.deletedicon:
(flags.unread && this.env.unreadicon ? this.env.unreadicon :
(flags.replied && this.env.repliedicon ? this.env.repliedicon : this.env.messageicon));
var col = document.createElement('TD');
col.className = 'icon';
col.innerHTML = icon ? '<img src="'+icon+'" alt="" border="0" />' : '';
row.appendChild(col);
// add each submitted col
- for (var c in cols)
- {
+ for (var n = 0; n < this.coltypes.length; n++)
+ {
+ var c = this.coltypes[n];
col = document.createElement('TD');
col.className = String(c).toLowerCase();
col.innerHTML = cols[c];
row.appendChild(col);
}
col = document.createElement('TD');
col.className = 'icon';
col.innerHTML = attachment && this.env.attachmenticon ? '<img src="'+this.env.attachmenticon+'" alt="" border="0" />' : '';
row.appendChild(col);
if (attop && tbody.rows.length)
tbody.insertBefore(row, tbody.firstChild);
else
tbody.appendChild(row);
this.init_message_row(row);
};
// replace content of row count display
this.set_rowcount = function(text)
{
if (this.gui_objects.countdisplay)
this.gui_objects.countdisplay.innerHTML = text;
// update page navigation buttons
this.set_page_buttons();
};
// replace content of quota display
this.set_quota = function(text)
{
if (this.gui_objects.quotadisplay)
this.gui_objects.quotadisplay.innerHTML = text;
};
// update the mailboxlist
this.set_unread_count = function(mbox, count, set_title)
{
if (!this.gui_objects.mailboxlist)
return false;
-
+
+ if (mbox==this.env.mailbox)
+ set_title = true;
+
var item, reg, text_obj;
mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
item = document.getElementById('rcmbx'+mbox);
if (item && 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, '');
-
+
// set the right classes
this.set_classname(item, 'unread', count>0 ? true : false);
}
// set unread count to window title
reg = /^\([0-9]+\)\s+/i;
- if (set_title && count && document.title)
+ if (set_title && document.title)
{
var doc_title = String(document.title);
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, '');
}
- // remove unread count from window title
- else if (document.title)
- {
- document.title = document.title.replace(reg, '');
- }
};
// add row to contacts list
this.add_contact_row = function(cid, cols)
{
if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
return false;
var tbody = this.gui_objects.contactslist.tBodies[0];
var rowcount = tbody.rows.length;
var even = rowcount%2;
var row = document.createElement('TR');
row.id = 'rcmrow'+cid;
row.className = 'contact '+(even ? 'even' : 'odd');
if (this.in_selection(cid))
row.className += ' selected';
// add each submitted col
for (var c in cols)
{
col = document.createElement('TD');
col.className = String(c).toLowerCase();
col.innerHTML = cols[c];
row.appendChild(col);
}
tbody.appendChild(row);
this.init_table_row(row, 'contact_rows');
};
/********************************************************/
/********* drag & drop methods *********/
/********************************************************/
this.drag_mouse_move = function(e)
{
if (this.drag_start)
{
if (!this.draglayer)
this.draglayer = new rcube_layer('rcmdraglayer', {x:0, y:0, width:300, vis:0, zindex:2000});
// get subjects of selectedd messages
var names = '';
var c, subject, obj;
for(var n=0; n<this.selection.length; n++)
{
if (n>12) // only show 12 lines
{
names += '...';
break;
}
if (this.message_rows[this.selection[n]].obj)
{
obj = this.message_rows[this.selection[n]].obj;
subject = '';
for(c=0; c<obj.childNodes.length; c++)
if (!subject && obj.childNodes[c].nodeName=='TD' && obj.childNodes[c].firstChild && obj.childNodes[c].firstChild.nodeType==3)
{
subject = obj.childNodes[c].firstChild.data;
names += (subject.length > 50 ? subject.substring(0, 50)+'...' : subject) + '<br />';
}
}
}
this.draglayer.write(names);
this.draglayer.show(1);
}
var pos = this.get_mouse_pos(e);
this.draglayer.move(pos.x+20, pos.y-5);
this.drag_start = false;
this.drag_active = true;
return false;
};
this.drag_mouse_up = function()
{
document.onmousemove = null;
if (this.draglayer && this.draglayer.visible)
this.draglayer.show(0);
this.drag_active = false;
return false;
};
/********************************************************/
/********* remote request methods *********/
/********************************************************/
this.http_sockets = new Array();
// find a non-busy socket or create a new one
this.get_request_obj = function()
{
for (var n=0; n<this.http_sockets.length; n++)
{
if (!this.http_sockets[n].busy)
return this.http_sockets[n];
}
// create a new XMLHTTP object
var i = this.http_sockets.length;
this.http_sockets[i] = new rcube_http_request();
return this.http_sockets[i];
};
// send a http request to the server
this.http_request = function(action, querystring, lock)
{
var request_obj = this.get_request_obj();
querystring += '&_remote=1';
// add timestamp to request url to avoid cacheing problems in Safari
if (bw.safari)
querystring += '&_ts='+(new Date().getTime());
// send request
if (request_obj)
{
// prompt('request', this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
console('HTTP request: '+this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
if (lock)
this.set_busy(true);
request_obj.__lock = lock ? true : false;
request_obj.__action = action;
request_obj.onerror = function(o){ rcube_webmail_client.http_error(o); };
request_obj.oncomplete = function(o){ rcube_webmail_client.http_response(o); };
request_obj.GET(this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
}
};
// handle HTTP response
this.http_response = function(request_obj)
{
var ctype = request_obj.get_header('Content-Type');
if (ctype){
ctype = String(ctype).toLowerCase();
var ctype_array=ctype.split(";");
ctype = ctype_array[0];
}
this.set_busy(false);
console(request_obj.get_text());
// if we get javascript code from server -> execute it
if (request_obj.get_text() && (ctype=='text/javascript' || ctype=='application/x-javascript'))
eval(request_obj.get_text());
// process the response data according to the sent action
switch (request_obj.__action)
{
case 'delete':
case 'moveto':
if (this.env.action=='show')
this.command('list');
break;
case 'list':
if (this.env.messagecount)
this.enable_command('purge', (this.env.mailbox==this.env.trash_mailbox));
case 'expunge':
this.enable_command('select-all', 'select-none', 'expunge', this.env.messagecount ? true : false);
break;
}
request_obj.reset();
};
// handle HTTP request errors
this.http_error = function(request_obj)
{
alert('Error sending request: '+request_obj.url);
if (request_obj.__lock)
this.set_busy(false);
request_obj.reset();
request_obj.__lock = false;
};
// use an image to send a keep-alive siganl to the server
this.send_keep_alive = function()
{
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()
{
this.set_busy(true, 'checkingmail');
var d = new Date();
this.http_request('check-recent', '_t='+d.getTime());
};
/********************************************************/
/********* helper methods *********/
/********************************************************/
// check if we're in show mode or if we have a unique selection
// and return the message uid
this.get_single_uid = function()
{
return this.env.uid ? this.env.uid : (this.selection.length==1 ? this.selection[0] : null);
};
// same as above but for contacts
this.get_single_cid = function()
{
return this.env.cid ? this.env.cid : (this.selection.length==1 ? this.selection[0] : null);
};
/* deprecated methods
// check if Shift-key is pressed on event
this.check_shiftkey = function(e)
{
if(!e && window.event)
e = window.event;
if(bw.linux && bw.ns4 && e.modifiers)
return true;
else if((bw.ns4 && e.modifiers & Event.SHIFT_MASK) || (e && e.shiftKey))
return true;
else
return false;
}
// check if Shift-key is pressed on event
this.check_ctrlkey = function(e)
{
if(!e && window.event)
e = window.event;
if(bw.linux && bw.ns4 && e.modifiers)
return true;
else if (bw.mac)
return this.check_shiftkey(e);
else if((bw.ns4 && e.modifiers & Event.CTRL_MASK) || (e && e.ctrlKey))
return true;
else
return false;
}
*/
// returns modifier key (constants defined at top of file)
this.get_modifier = function(e)
{
var opcode = 0;
e = e || window.event;
if (bw.mac && e)
{
opcode += (e.metaKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
return opcode;
}
if (e)
{
opcode += (e.ctrlKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
return opcode;
}
if (e.cancelBubble)
{
e.cancelBubble = true;
e.returnValue = false;
}
else if (e.preventDefault)
e.preventDefault();
}
this.get_mouse_pos = function(e)
{
if(!e) e = window.event;
var mX = (e.pageX) ? e.pageX : e.clientX;
var mY = (e.pageY) ? e.pageY : e.clientY;
if(document.body && document.all)
{
mX += document.body.scrollLeft;
mY += document.body.scrollTop;
}
return { x:mX, y:mY };
};
this.get_caret_pos = function(obj)
{
if (typeof(obj.selectionEnd)!='undefined')
return obj.selectionEnd;
else if (document.selection && document.selection.createRange)
{
var range = document.selection.createRange();
if (range.parentElement()!=obj)
return 0;
var gm = range.duplicate();
if (obj.tagName=='TEXTAREA')
gm.moveToElementText(obj);
else
gm.expand('textedit');
gm.setEndPoint('EndToStart', range);
var p = gm.text.length;
return p<=obj.value.length ? p : -1;
}
else
return obj.value.length;
};
this.set_caret2start = function(obj)
{
if (obj.createTextRange)
{
var range = obj.createTextRange();
range.collapse(true);
range.select();
}
else if (obj.setSelectionRange)
obj.setSelectionRange(0,0);
obj.focus();
};
// set all fields of a form disabled
this.lock_form = function(form, lock)
{
if (!form || !form.elements)
return;
var type;
for (var n=0; n<form.elements.length; n++)
{
type = form.elements[n];
if (type=='hidden')
continue;
form.elements[n].disabled = lock;
}
};
} // end object rcube_webmail
// class for HTTP requests
function rcube_http_request()
{
this.url = '';
this.busy = false;
this.xmlhttp = null;
// reset object properties
this.reset = function()
{
// set unassigned event handlers
this.onloading = function(){ };
this.onloaded = function(){ };
this.oninteractive = function(){ };
this.oncomplete = function(){ };
this.onabort = function(){ };
this.onerror = function(){ };
this.url = '';
this.busy = false;
this.xmlhttp = null;
}
// create HTMLHTTP object
this.build = function()
{
if (window.XMLHttpRequest)
this.xmlhttp = new XMLHttpRequest();
else if (window.ActiveXObject)
this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
else
{
}
}
// sedn GET request
this.GET = function(url)
{
this.build();
if (!this.xmlhttp)
{
this.onerror(this);
return false;
}
var ref = this;
this.url = url;
this.busy = true;
this.xmlhttp.onreadystatechange = function(){ ref.xmlhttp_onreadystatechange(); };
this.xmlhttp.open('GET', url);
this.xmlhttp.send(null);
};
this.POST = function(url, a_param)
{
// not implemented yet
};
// handle onreadystatechange event
this.xmlhttp_onreadystatechange = function()
{
if(this.xmlhttp.readyState == 1)
this.onloading(this);
else if(this.xmlhttp.readyState == 2)
this.onloaded(this);
else if(this.xmlhttp.readyState == 3)
this.oninteractive(this);
else if(this.xmlhttp.readyState == 4)
{
if(this.xmlhttp.status == 0)
this.onabort(this);
else if(this.xmlhttp.status == 200)
this.oncomplete(this);
else
this.onerror(this);
this.busy = false;
}
}
// getter method for HTTP headers
this.get_header = function(name)
{
return this.xmlhttp.getResponseHeader(name);
};
this.get_text = function()
{
return this.xmlhttp.responseText;
};
this.get_xml = function()
{
return this.xmlhttp.responseXML;
};
this.reset();
} // end class rcube_http_request
function console(str)
{
if (document.debugform && document.debugform.console)
document.debugform.console.value += str+'\n--------------------------------------\n';
}
// set onload handler
window.onload = function(e)
{
if (window.rcube_webmail_client)
rcube_webmail_client.init();
};
diff --git a/program/lib/imap.inc b/program/lib/imap.inc
index 51db669c6..b8f3dea39 100644
--- a/program/lib/imap.inc
+++ b/program/lib/imap.inc
@@ -1,2110 +1,2110 @@
<?php
/////////////////////////////////////////////////////////
//
// Iloha IMAP Library (IIL)
//
// (C)Copyright 2002 Ryo Chijiiwa <Ryo@IlohaMail.org>
//
// This file is part of IlohaMail. IlohaMail is free software released
// under the GPL license. See enclosed file COPYING for details, or
// see http://www.fsf.org/copyleft/gpl.html
//
/////////////////////////////////////////////////////////
/********************************************************
FILE: include/imap.inc
PURPOSE:
Provide alternative IMAP library that doesn't rely on the standard
C-Client based version. This allows IlohaMail to function regardless
of whether or not the PHP build it's running on has IMAP functionality
built-in.
USEAGE:
Function containing "_C_" in name require connection handler to be
passed as one of the parameters. To obtain connection handler, use
iil_Connect()
VERSION:
IlohaMail-0.9-20050415
CHANGES:
File altered by Thomas Bruederli <roundcube@gmail.com>
to fit enhanced equirements by the RoundCube Webmail:
- Added list of server capabilites and check these before invoking commands
- Added junk flag to iilBasicHeader
- Enhanced error reporting on fsockopen()
- Additional parameter for SORT command
- Removed Call-time pass-by-reference because deprecated
- Parse charset from content-type in iil_C_FetchHeaders()
- Enhanced heaer sorting
- Pass message as reference in iil_C_Append (to save memory)
- Added BCC and REFERENCE to the list of headers to fetch in iil_C_FetchHeaders()
- Leave messageID unchanged in iil_C_FetchHeaders()
- Avoid stripslahes in iil_Connect()
- Added patch to iil_SortHeaders() by Richard Green
- Removed <br> from error messages (better for logging)
- Added patch to iil_C_Sort() enabling UID SORT commands
- Added function iil_C_ID2UID()
- Casting date parts in iil_StrToTime() to avoid mktime() warnings
- Removed some debuggers (echo ...)
********************************************************/
// changed path to work within roundcube webmail
include_once("lib/icl_commons.inc");
if (!$IMAP_USE_HEADER_DATE) $IMAP_USE_INTERNAL_DATE = true;
$IMAP_MONTHS=array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
$IMAP_SERVER_TZ = date('Z');
$iil_error;
$iil_errornum;
$iil_selected;
class iilConnection{
var $fp;
var $error;
var $errorNum;
var $selected;
var $message;
var $host;
var $cache;
var $uid_cache;
var $do_cache;
var $exists;
var $recent;
var $rootdir;
var $delimiter;
var $capability = array();
}
class iilBasicHeader{
var $id;
var $uid;
var $subject;
var $from;
var $to;
var $cc;
var $replyto;
var $in_reply_to;
var $date;
var $messageID;
var $size;
var $encoding;
var $ctype;
var $flags;
var $timestamp;
var $f;
var $seen;
var $deleted;
var $recent;
var $answered;
var $junk;
var $internaldate;
var $is_reply;
}
class iilThreadHeader{
var $id;
var $sbj;
var $irt;
var $mid;
}
function iil_xor($string, $string2){
$result = "";
$size = strlen($string);
for ($i=0; $i<$size; $i++) $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
return $result;
}
function iil_ReadLine($fp, $size){
$line="";
if ($fp){
do{
$buffer = fgets($fp, 2048);
$line.=$buffer;
}while($buffer[strlen($buffer)-1]!="\n");
}
return $line;
}
function iil_MultLine($fp, $line){
$line = chop($line);
if (ereg('\{[0-9]+\}$', $line)){
$out = "";
preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a);
$bytes = $a[2][0];
while(strlen($out)<$bytes){
$out.=chop(iil_ReadLine($fp, 1024));
}
$line = $a[1][0]."\"$out\"";
}
return $line;
}
function iil_ReadBytes($fp, $bytes){
$data = "";
$len = 0;
do{
$data.=fread($fp, $bytes-$len);
$len = strlen($data);
}while($len<$bytes);
return $data;
}
function iil_ReadReply($fp){
do{
$line = chop(trim(iil_ReadLine($fp, 1024)));
}while($line[0]=="*");
return $line;
}
function iil_ParseResult($string){
$a=explode(" ", $string);
if (count($a) > 2){
if (strcasecmp($a[1], "OK")==0) return 0;
else if (strcasecmp($a[1], "NO")==0) return -1;
else if (strcasecmp($a[1], "BAD")==0) return -2;
}else return -3;
}
// check if $string starts with $match
function iil_StartsWith($string, $match){
$len = strlen($match);
if ($len==0) return false;
if (strncmp($string, $match, $len)==0) return true;
else return false;
}
function iil_StartsWithI($string, $match){
$len = strlen($match);
if ($len==0) return false;
if (strncasecmp($string, $match, $len)==0) return true;
else return false;
}
function iil_C_Authenticate(&$conn, $user, $pass, $encChallenge){
// initialize ipad, opad
for ($i=0;$i<64;$i++){
$ipad.=chr(0x36);
$opad.=chr(0x5C);
}
// pad $pass so it's 64 bytes
$padLen = 64 - strlen($pass);
for ($i=0;$i<$padLen;$i++) $pass .= chr(0);
// generate hash
$hash = md5(iil_xor($pass,$opad).pack("H*",md5(iil_xor($pass, $ipad).base64_decode($encChallenge))));
// generate reply
$reply = base64_encode($user." ".$hash);
// send result, get reply
fputs($conn->fp, $reply."\r\n");
$line = iil_ReadLine($conn->fp, 1024);
// process result
if (iil_ParseResult($line)==0){
$conn->error .= "";
$conn->errorNum = 0;
return $conn->fp;
}else{
$conn->error .= 'Authentication for '.$user.' failed (AUTH): "'.htmlspecialchars($line)."\"";
$conn->errorNum = -2;
return false;
}
}
function iil_C_Login(&$conn, $user, $password){
fputs($conn->fp, "a001 LOGIN $user \"$password\"\r\n");
do{
$line = iil_ReadReply($conn->fp);
}while(!iil_StartsWith($line, "a001 "));
$a=explode(" ", $line);
if (strcmp($a[1],"OK")==0){
$result=$conn->fp;
$conn->error.="";
$conn->errorNum = 0;
}else{
$result=false;
fclose($conn->fp);
$conn->error .= 'Authentication for '.$user.' failed (LOGIN): "'.htmlspecialchars($line)."\"";
$conn->errorNum = -2;
}
return $result;
}
function iil_ParseNamespace2($str, &$i, $len=0, $l){
if (!$l) $str = str_replace("NIL", "()", $str);
if (!$len) $len = strlen($str);
$data = array();
$in_quotes = false;
$elem = 0;
for($i;$i<$len;$i++){
$c = (string)$str[$i];
if ($c=='(' && !$in_quotes){
$i++;
$data[$elem] = iil_ParseNamespace2($str, $i, $len, $l++);
$elem++;
}else if ($c==')' && !$in_quotes) return $data;
else if ($c=="\\"){
$i++;
if ($in_quotes) $data[$elem].=$c.$str[$i];
}else if ($c=='"'){
$in_quotes = !$in_quotes;
if (!$in_quotes) $elem++;
}else if ($in_quotes){
$data[$elem].=$c;
}
}
return $data;
}
function iil_C_NameSpace(&$conn){
global $my_prefs;
if (!in_array('NAMESPACE', $conn->capability))
return false;
if ($my_prefs["rootdir"]) return true;
fputs($conn->fp, "ns1 NAMESPACE\r\n");
do{
$line = iil_ReadLine($conn->fp, 1024);
if (iil_StartsWith($line, "* NAMESPACE")){
$i = 0;
$data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
}
}while(!iil_StartsWith($line, "ns1"));
if (!is_array($data)) return false;
$user_space_data = $data[0];
if (!is_array($user_space_data)) return false;
$first_userspace = $user_space_data[0];
if (count($first_userspace)!=2) return false;
$conn->rootdir = $first_userspace[0];
$conn->delimiter = $first_userspace[1];
$my_prefs["rootdir"] = substr($conn->rootdir, 0, -1);
return true;
}
function iil_Connect($host, $user, $password){
global $iil_error, $iil_errornum;
global $ICL_SSL, $ICL_PORT;
global $IMAP_NO_CACHE;
global $my_prefs, $IMAP_USE_INTERNAL_DATE;
$iil_error = "";
$iil_errornum = 0;
//strip slashes
// $user = stripslashes($user);
// $password = stripslashes($password);
//set auth method
$auth_method = "plain";
if (func_num_args() >= 4){
$auth_array = func_get_arg(3);
if (is_array($auth_array)) $auth_method = $auth_array["imap"];
if (empty($auth_method)) $auth_method = "plain";
}
$message = "INITIAL: $auth_method\n";
$result = false;
//initialize connection
$conn = new iilConnection;
$conn->error="";
$conn->errorNum=0;
$conn->selected="";
$conn->user = $user;
$conn->host = $host;
$conn->cache = array();
$conn->do_cache = (function_exists("cache_write")&&!$IMAP_NO_CACHE);
$conn->cache_dirty = array();
if ($my_prefs['sort_field']=='INTERNALDATE') $IMAP_USE_INTERNAL_DATE = true;
else if ($my_prefs['sort_field']=='DATE') $IMAP_USE_INTERNAL_DATE = false;
//echo '<!-- conn sort_field: '.$my_prefs['sort_field'].' //-->';
//check input
if (empty($host)) $iil_error .= "Invalid host\n";
if (empty($user)) $iil_error .= "Invalid user\n";
if (empty($password)) $iil_error .= "Invalid password\n";
if (!empty($iil_error)) return false;
if (!$ICL_PORT) $ICL_PORT = 143;
//check for SSL
if ($ICL_SSL){
$host = "ssl://".$host;
}
//open socket connection
$conn->fp = @fsockopen($host, $ICL_PORT, $errno, $errstr, 10);
if (!$conn->fp){
$iil_error = "Could not connect to $host at port $ICL_PORT: $errstr";
$iil_errornum = -1;
return false;
}
$iil_error.="Socket connection established\r\n";
$line=iil_ReadLine($conn->fp, 300);
if (strcasecmp($auth_method, "check")==0){
//check for supported auth methods
//default to plain text auth
$auth_method = "plain";
//check for CRAM-MD5
fputs($conn->fp, "cp01 CAPABILITY\r\n");
do{
$line = trim(chop(iil_ReadLine($conn->fp, 100)));
$conn->message.="$line\n";
$a = explode(" ", $line);
if ($line[0]=="*"){
while ( list($k, $w) = each($a) ){
if ($w!='*' && $w!='CAPABILITY')
$conn->capability[] = $w;
if ((strcasecmp($w, "AUTH=CRAM_MD5")==0)||
(strcasecmp($w, "AUTH=CRAM-MD5")==0)){
$auth_method = "auth";
}
}
}
}while($a[0]!="cp01");
}
if (strcasecmp($auth_method, "auth")==0){
$conn->message.="Trying CRAM-MD5\n";
//do CRAM-MD5 authentication
fputs($conn->fp, "a000 AUTHENTICATE CRAM-MD5\r\n");
$line = trim(chop(iil_ReadLine($conn->fp, 1024)));
$conn->message.="$line\n";
if ($line[0]=="+"){
$conn->message.='Got challenge: '.htmlspecialchars($line)."\n";
//got a challenge string, try CRAM-5
$result = iil_C_Authenticate($conn, $user, $password, substr($line,2));
$conn->message.= "Tried CRAM-MD5: $result \n";
}else{
$conn->message.='No challenge ('.htmlspecialchars($line)."), try plain\n";
$auth = "plain";
}
}
if ((!$result)||(strcasecmp($auth, "plain")==0)){
//do plain text auth
$result = iil_C_Login($conn, $user, $password);
$conn->message.="Tried PLAIN: $result \n";
}
$conn->message .= $auth;
if ($result){
iil_C_Namespace($conn);
return $conn;
}else{
$iil_error = $conn->error;
$iil_errornum = $conn->errorNum;
return false;
}
}
function iil_Close(&$conn){
iil_C_WriteCache($conn);
if (@fputs($conn->fp, "I LOGOUT\r\n")){
fgets($conn->fp, 1024);
fclose($conn->fp);
$conn->fp = false;
}
}
function iil_ClearCache($user, $host){
}
function iil_C_WriteCache(&$conn){
//echo "<!-- doing iil_C_WriteCache //-->\n";
if (!$conn->do_cache) return false;
if (is_array($conn->cache)){
while(list($folder,$data)=each($conn->cache)){
if ($folder && is_array($data) && $conn->cache_dirty[$folder]){
$key = $folder.".imap";
$result = cache_write($conn->user, $conn->host, $key, $data, true);
//echo "<!-- writing $key $data: $result //-->\n";
}
}
}
}
function iil_C_EnableCache(&$conn){
$conn->do_cache = true;
}
function iil_C_DisableCache(&$conn){
$conn->do_cache = false;
}
function iil_C_LoadCache(&$conn, $folder){
if (!$conn->do_cache) return false;
$key = $folder.".imap";
if (!is_array($conn->cache[$folder])){
$conn->cache[$folder] = cache_read($conn->user, $conn->host, $key);
$conn->cache_dirty[$folder] = false;
}
}
function iil_C_ExpireCachedItems(&$conn, $folder, $message_set){
if (!$conn->do_cache) return; //caching disabled
if (!is_array($conn->cache[$folder])) return; //cache not initialized|empty
if (count($conn->cache[$folder])==0) return; //cache not initialized|empty
$uids = iil_C_FetchHeaderIndex($conn, $folder, $message_set, "UID");
$num_removed = 0;
if (is_array($uids)){
//echo "<!-- unsetting: ".implode(",",$uids)." //-->\n";
while(list($n,$uid)=each($uids)){
unset($conn->cache[$folder][$uid]);
//$conn->cache[$folder][$uid] = false;
//$num_removed++;
}
$conn->cache_dirty[$folder] = true;
//echo '<!--'."\n";
//print_r($conn->cache);
//echo "\n".'//-->'."\n";
}else{
echo "<!-- failed to get uids: $message_set //-->\n";
}
/*
if ($num_removed>0){
$new_cache;
reset($conn->cache[$folder]);
while(list($uid,$item)=each($conn->cache[$folder])){
if ($item) $new_cache[$uid] = $conn->cache[$folder][$uid];
}
$conn->cache[$folder] = $new_cache;
}
*/
}
function iil_ExplodeQuotedString($delimiter, $string){
$quotes=explode("\"", $string);
while ( list($key, $val) = each($quotes))
if (($key % 2) == 1)
$quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]);
$string=implode("\"", $quotes);
$result=explode($delimiter, $string);
while ( list($key, $val) = each($result) )
$result[$key] = str_replace("_!@!_", $delimiter, $result[$key]);
return $result;
}
function iil_CheckForRecent($host, $user, $password, $mailbox){
if (empty($mailbox)) $mailbox="INBOX";
$conn=iil_Connect($host, $user, $password, "plain");
$fp = $conn->fp;
if ($fp){
fputs($fp, "a002 EXAMINE \"$mailbox\"\r\n");
do{
$line=chop(iil_ReadLine($fp, 300));
$a=explode(" ", $line);
if (($a[0]=="*") && (strcasecmp($a[2], "RECENT")==0)) $result=(int)$a[1];
}while (!iil_StartsWith($a[0],"a002"));
fputs($fp, "a003 LOGOUT\r\n");
fclose($fp);
}else $result=-2;
return $result;
}
function iil_C_Select(&$conn, $mailbox){
$fp = $conn->fp;
if (empty($mailbox)) return false;
if (strcmp($conn->selected, $mailbox)==0) return true;
iil_C_LoadCache($conn, $mailbox);
if (fputs($fp, "sel1 SELECT \"$mailbox\"\r\n")){
do{
$line=chop(iil_ReadLine($fp, 300));
$a=explode(" ", $line);
if (count($a) == 3){
if (strcasecmp($a[2], "EXISTS")==0) $conn->exists=(int)$a[1];
if (strcasecmp($a[2], "RECENT")==0) $conn->recent=(int)$a[1];
}
}while (!iil_StartsWith($line, "sel1"));
$a=explode(" ", $line);
if (strcasecmp($a[1],"OK")==0){
$conn->selected = $mailbox;
return true;
}else return false;
}else{
return false;
}
}
function iil_C_CheckForRecent(&$conn, $mailbox){
if (empty($mailbox)) $mailbox="INBOX";
iil_C_Select($conn, $mailbox);
if ($conn->selected==$mailbox) return $conn->recent;
else return false;
}
function iil_C_CountMessages(&$conn, $mailbox, $refresh=false){
if ($refresh) $conn->selected="";
iil_C_Select($conn, $mailbox);
if ($conn->selected==$mailbox) return $conn->exists;
else return false;
}
function iil_SplitHeaderLine($string){
$pos=strpos($string, ":");
if ($pos>0){
$res[0]=substr($string, 0, $pos);
$res[1]=trim(substr($string, $pos+1));
return $res;
}else{
return $string;
}
}
function iil_StrToTime($str){
global $IMAP_MONTHS,$IMAP_SERVER_TZ;
if ($str) $time1 = strtotime($str);
if ($time1 && $time1!=-1) return $time1-$IMAP_SERVER_TZ;
//echo '<!--'.$str.'//-->';
//replace double spaces with single space
$str = trim($str);
$str = str_replace(" ", " ", $str);
//strip off day of week
$pos=strpos($str, " ");
if (!is_numeric(substr($str, 0, $pos))) $str = substr($str, $pos+1);
//explode, take good parts
$a=explode(" ",$str);
//$month_a=array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
$month_str=$a[1];
$month=$IMAP_MONTHS[$month_str];
$day=(int)$a[0];
$year=(int)$a[2];
$time=$a[3];
$tz_str = $a[4];
$tz = substr($tz_str, 0, 3);
$ta = explode(":",$time);
$hour=(int)$ta[0]-(int)$tz;
$minute=(int)$ta[1];
$second=(int)$ta[2];
//make UNIX timestamp
$time2 = mktime($hour, $minute, $second, $month, $day, $year);
//echo '<!--'.$time1.' '.$time2.' //-->'."\n";
return $time2;
}
function iil_C_Sort(&$conn, $mailbox, $field, $add='', $is_uid=FALSE, $encoding='US-ASCII'){
/* Do "SELECT" command */
if (!iil_C_Select($conn, $mailbox)) return false;
$field = strtoupper($field);
if ($field=='INTERNALDATE') $field='ARRIVAL';
$fields = array('ARRIVAL'=>1,'CC'=>1,'DATE'=>1,'FROM'=>1,'SIZE'=>1,'SUBJECT'=>1,'TO'=>1);
if (!$fields[$field])
return false;
$is_uid = $is_uid ? 'UID ' : '';
if (!empty($add))
$add = " $add";
$fp = $conn->fp;
$command = 's '. $is_uid .'SORT ('.$field.') '.$encoding.' ALL'."$add\r\n";
$line = $data = '';
if (!fputs($fp, $command)) return false;
do{
$line = chop(iil_ReadLine($fp, 1024));
if (iil_StartsWith($line, '* SORT')) $data.=($data?' ':'').substr($line,7);
}while($line[0]!='s');
if (empty($data)){
$conn->error = $line;
return false;
}
$out = explode(' ',$data);
return $out;
}
function iil_C_FetchHeaderIndex(&$conn, $mailbox, $message_set, $index_field, $normalize=true){
global $IMAP_USE_INTERNAL_DATE;
$c=0;
$result=array();
$fp = $conn->fp;
if (empty($index_field)) $index_field="DATE";
$index_field = strtoupper($index_field);
- if (empty($message_set)) return array();
+ if ((empty($message_set)) || ($message_set == "1:0")) return array();
//$fields_a["DATE"] = ($IMAP_USE_INTERNAL_DATE?6:1);
$fields_a['DATE'] = 1;
$fields_a['INTERNALDATE'] = 6;
$fields_a['FROM'] = 1;
$fields_a['REPLY-TO'] = 1;
$fields_a['SENDER'] = 1;
$fields_a['TO'] = 1;
$fields_a['SUBJECT'] = 1;
$fields_a['UID'] = 2;
$fields_a['SIZE'] = 2;
$fields_a['SEEN'] = 3;
$fields_a['RECENT'] = 4;
$fields_a['DELETED'] = 5;
$mode=$fields_a[$index_field];
if (!($mode > 0)) return false;
/* Do "SELECT" command */
if (!iil_C_Select($conn, $mailbox)) return false;
/* FETCH date,from,subject headers */
if ($mode==1){
$key="fhi".($c++);
$request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)])\r\n";
if (!fputs($fp, $request)) return false;
do{
$line=chop(iil_ReadLine($fp, 200));
$a=explode(" ", $line);
if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[strlen($line)-1]!=")")){
$id=$a[1];
$str=$line=chop(iil_ReadLine($fp, 300));
while($line[0]!=")"){ //caution, this line works only in this particular case
$line=chop(iil_ReadLine($fp, 300));
if ($line[0]!=")"){
if (ord($line[0]) <= 32){ //continuation from previous header line
$str.=" ".trim($line);
}
if ((ord($line[0]) > 32) || (strlen($line[0]) == 0)){
list($field, $string) = iil_SplitHeaderLine($str);
if (strcasecmp($field, "date")==0){
$result[$id]=iil_StrToTime($string);
}else{
$result[$id] = str_replace("\"", "", $string);
if ($normalize) $result[$id]=strtoupper($result[$id]);
}
$str=$line;
}
}
}
}
/*
$end_pos = strlen($line)-1;
if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[$end_pos]=="}")){
$id = $a[1];
$pos = strrpos($line, "{")+1;
$bytes = (int)substr($line, $pos, $end_pos-$pos);
$received = 0;
do{
$line = iil_ReadLine($fp, 0);
$received+=strlen($line);
$line = chop($line);
if ($received>$bytes) break;
else if (!$line) continue;
list($field,$string)=explode(": ", $line);
if (strcasecmp($field, "date")==0)
$result[$id] = iil_StrToTime($string);
else if ($index_field!="DATE")
$result[$id]=strtoupper(str_replace("\"", "", $string));
}while($line[0]!=")");
}else{
//one line response, not expected so ignore
}
*/
}while(!iil_StartsWith($line, $key));
}else if ($mode==6){
$key="fhi".($c++);
$request = $key." FETCH $message_set (INTERNALDATE)\r\n";
if (!fputs($fp, $request)) return false;
do{
$line=chop(iil_ReadLine($fp, 200));
if ($line[0]=="*"){
//original: "* 10 FETCH (INTERNALDATE "31-Jul-2002 09:18:02 -0500")"
$paren_pos = strpos($line, "(");
$foo = substr($line, 0, $paren_pos);
$a = explode(" ", $foo);
$id = $a[1];
$open_pos = strpos($line, "\"") + 1;
$close_pos = strrpos($line, "\"");
if ($open_pos && $close_pos){
$len = $close_pos - $open_pos;
$time_str = substr($line, $open_pos, $len);
$result[$id] = strtotime($time_str);
}
}else{
$a = explode(" ", $line);
}
}while(!iil_StartsWith($a[0], $key));
}else{
if ($mode >= 3) $field_name="FLAGS";
else if ($index_field=="SIZE") $field_name="RFC822.SIZE";
else $field_name=$index_field;
/* FETCH uid, size, flags */
$key="fhi".($c++);
$request=$key." FETCH $message_set ($field_name)\r\n";
if (!fputs($fp, $request)) return false;
do{
$line=chop(iil_ReadLine($fp, 200));
$a = explode(" ", $line);
if (($line[0]=="*") && ($a[2]=="FETCH")){
$line=str_replace("(", "", $line);
$line=str_replace(")", "", $line);
$a=explode(" ", $line);
$id=$a[1];
if (isset($result[$id])) continue; //if we already got the data, skip forward
if ($a[3]!=$field_name) continue; //make sure it's returning what we requested
/* Caution, bad assumptions, next several lines */
if ($mode==2) $result[$id]=$a[4];
else{
$haystack=strtoupper($line);
$result[$id]=(strpos($haystack, $index_field) > 0 ? "F" : "N");
}
}
}while(!iil_StartsWith($line, $key));
}
//check number of elements...
list($start_mid,$end_mid)=explode(':',$message_set);
if (is_numeric($start_mid) && is_numeric($end_mid)){
//count how many we should have
$should_have = $end_mid - $start_mid +1;
//if we have less, try and fill in the "gaps"
if (count($result)<$should_have){
for($i=$start_mid;$i<=$end_mid;$i++) if (!isset($result[$i])) $result[$i] = '';
}
}
return $result;
}
function iil_CompressMessageSet($message_set){
//given a comma delimited list of independent mid's,
//compresses by grouping sequences together
//if less than 255 bytes long, let's not bother
if (strlen($message_set)<255) return $message_set;
//see if it's already been compress
if (strpos($message_set,':')!==false) return $message_set;
//separate, then sort
$ids = explode(',',$message_set);
sort($ids);
$result = array();
$start = $prev = $ids[0];
foreach($ids as $id){
$incr = $id - $prev;
if ($incr>1){ //found a gap
if ($start==$prev) $result[] = $prev; //push single id
else $result[] = $start.':'.$prev; //push sequence as start_id:end_id
$start = $id; //start of new sequence
}
$prev = $id;
}
//handle the last sequence/id
if ($start==$prev) $result[] = $prev;
else $result[] = $start.':'.$prev;
//return as comma separated string
return implode(',',$result);
}
function iil_C_UIDsToMIDs(&$conn, $mailbox, $uids){
if (!is_array($uids) || count($uids)==0) return array();
return iil_C_Search($conn, $mailbox, "UID ".implode(",", $uids));
}
function iil_C_UIDToMID(&$conn, $mailbox, $uid){
$result = iil_C_UIDsToMIDs($conn, $mailbox, array($uid));
if (count($result)==1) return $result[0];
else return false;
}
function iil_C_FetchUIDs(&$conn,$mailbox){
global $clock;
$num = iil_C_CountMessages($conn, $mailbox);
if ($num==0) return array();
$message_set = '1'.($num>1?':'.$num:'');
//if cache not enabled, just call iil_C_FetchHeaderIndex on 'UID' field
if (!$conn->do_cache)
return iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
//otherwise, let's check cache first
$key = $mailbox.'.uids';
$cache_good = true;
if ($conn->uid_cache) $data = $conn->uid_cache;
else $data = cache_read($conn->user, $conn->host, $key);
//was anything cached at all?
if ($data===false) $cache_good = -1;
//make sure number of messages were the same
if ($cache_good>0 && $data['n']!=$num) $cache_good = -2;
//if everything's okay so far...
if ($cache_good>0){
//check UIDs of highest mid with current and cached
$temp = iil_C_Search($conn, $mailbox, 'UID '.$data['d'][$num]);
if (!$temp || !is_array($temp) || $temp[0]!=$num) $cache_good=-3;
}
//if cached data's good, return it
if ($cache_good>0){
return $data['d'];
}
//otherwise, we need to fetch it
$data = array('n'=>$num,'d'=>array());
$data['d'] = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
cache_write($conn->user, $conn->host, $key, $data);
$conn->uid_cache = $data;
return $data['d'];
}
function iil_SortThreadHeaders($headers, $index_a, $uids){
asort($index_a);
$result = array();
foreach($index_a as $mid=>$foobar){
$uid = $uids[$mid];
$result[$uid] = $headers[$uid];
}
return $result;
}
function iil_C_FetchThreadHeaders(&$conn, $mailbox, $message_set){
global $clock;
global $index_a;
if (empty($message_set)) return false;
$result = array();
$uids = iil_C_FetchUIDs($conn, $mailbox);
$debug = false;
/* Get cached records where possible */
if ($conn->do_cache){
$cached = cache_read($conn->user, $conn->host, $mailbox.'.thhd');
if ($cached && is_array($uids) && count($uids)>0){
$needed_set = "";
foreach($uids as $id=>$uid){
if ($cached[$uid]){
$result[$uid] = $cached[$uid];
$result[$uid]->id = $id;
}else $needed_set.=($needed_set?",":"").$id;
}
if ($needed_set) $message_set = $needed_set;
else $message_set = '';
}
}
$message_set = iil_CompressMessageSet($message_set);
if ($debug) echo "Still need: ".$message_set;
/* if we're missing any, get them */
if ($message_set){
/* FETCH date,from,subject headers */
$key="fh";
$fp = $conn->fp;
$request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS (SUBJECT MESSAGE-ID IN-REPLY-TO)])\r\n";
$mid_to_id = array();
if (!fputs($fp, $request)) return false;
do{
$line = chop(iil_ReadLine($fp, 1024));
if ($debug) echo $line."\n";
if (ereg('\{[0-9]+\}$', $line)){
$a = explode(" ", $line);
$new = array();
$new_thhd = new iilThreadHeader;
$new_thhd->id = $a[1];
do{
$line=chop(iil_ReadLine($fp, 1024),"\r\n");
if (iil_StartsWithI($line,'Message-ID:') || (iil_StartsWithI($line,'In-Reply-To:')) || (iil_StartsWithI($line,'SUBJECT:'))){
$pos = strpos($line, ":");
$field_name = substr($line, 0, $pos);
$field_val = substr($line, $pos+1);
$new[strtoupper($field_name)] = trim($field_val);
}else if (ereg('^[[:space:]]', $line)){
$new[strtoupper($field_name)].= trim($line);
}
}while($line[0]!=')');
$new_thhd->sbj = $new['SUBJECT'];
$new_thhd->mid = substr($new['MESSAGE-ID'], 1, -1);
$new_thhd->irt = substr($new['IN-REPLY-TO'], 1, -1);
$result[$uids[$new_thhd->id]] = $new_thhd;
}
}while(!iil_StartsWith($line, "fh"));
}
/* sort headers */
if (is_array($index_a)){
$result = iil_SortThreadHeaders($result, $index_a, $uids);
}
/* write new set to cache */
if ($conn->do_cache){
if (count($result)!=count($cached))
cache_write($conn->user, $conn->host, $mailbox.'.thhd', $result);
}
//echo 'iil_FetchThreadHeaders:'."\n";
//print_r($result);
return $result;
}
function iil_C_BuildThreads2(&$conn, $mailbox, $message_set, &$clock){
global $index_a;
if (empty($message_set)) return false;
$result=array();
$roots=array();
$root_mids = array();
$sub_mids = array();
$strays = array();
$messages = array();
$fp = $conn->fp;
$debug = false;
$sbj_filter_pat = '[a-zA-Z]{2,3}(\[[0-9]*\])?:([[:space:]]*)';
/* Do "SELECT" command */
if (!iil_C_Select($conn, $mailbox)) return false;
/* FETCH date,from,subject headers */
$mid_to_id = array();
$messages = array();
$headers = iil_C_FetchThreadHeaders($conn, $mailbox, $message_set);
if ($clock) $clock->register('fetched headers');
if ($debug) print_r($headers);
/* go through header records */
foreach($headers as $header){
//$id = $header['i'];
//$new = array('id'=>$id, 'MESSAGE-ID'=>$header['m'],
// 'IN-REPLY-TO'=>$header['r'], 'SUBJECT'=>$header['s']);
$id = $header->id;
$new = array('id'=>$id, 'MESSAGE-ID'=>$header->mid,
'IN-REPLY-TO'=>$header->irt, 'SUBJECT'=>$header->sbj);
/* add to message-id -> mid lookup table */
$mid_to_id[$new['MESSAGE-ID']] = $id;
/* if no subject, use message-id */
if (empty($new['SUBJECT'])) $new['SUBJECT'] = $new['MESSAGE-ID'];
/* if subject contains 'RE:' or has in-reply-to header, it's a reply */
$sbj_pre ='';
$has_re = false;
if (eregi($sbj_filter_pat, $new['SUBJECT'])) $has_re = true;
if ($has_re||$new['IN-REPLY-TO']) $sbj_pre = 'RE:';
/* strip out 're:', 'fw:' etc */
if ($has_re) $sbj = ereg_replace($sbj_filter_pat,'', $new['SUBJECT']);
else $sbj = $new['SUBJECT'];
$new['SUBJECT'] = $sbj_pre.$sbj;
/* if subject not a known thread-root, add to list */
if ($debug) echo $id.' '.$new['SUBJECT']."\t".$new['MESSAGE-ID']."\n";
$root_id = $roots[$sbj];
if ($root_id && ($has_re || !$root_in_root[$root_id])){
if ($debug) echo "\tfound root: $root_id\n";
$sub_mids[$new['MESSAGE-ID']] = $root_id;
$result[$root_id][] = $id;
}else if (!isset($roots[$sbj])||(!$has_re&&$root_in_root[$root_id])){
/* try to use In-Reply-To header to find root
unless subject contains 'Re:' */
if ($has_re&&$new['IN-REPLY-TO']){
if ($debug) echo "\tlooking: ".$new['IN-REPLY-TO']."\n";
//reply to known message?
$temp = $sub_mids[$new['IN-REPLY-TO']];
if ($temp){
//found it, root:=parent's root
if ($debug) echo "\tfound parent: ".$new['SUBJECT']."\n";
$result[$temp][] = $id;
$sub_mids[$new['MESSAGE-ID']] = $temp;
$sbj = '';
}else{
//if we can't find referenced parent, it's a "stray"
$strays[$id] = $new['IN-REPLY-TO'];
}
}
//add subject as root
if ($sbj){
if ($debug) echo "\t added to root\n";
$roots[$sbj] = $id;
$root_in_root[$id] = !$has_re;
$sub_mids[$new['MESSAGE-ID']] = $id;
$result[$id] = array($id);
}
if ($debug) echo $new['MESSAGE-ID']."\t".$sbj."\n";
}
}
//now that we've gone through all the messages,
//go back and try and link up the stray threads
if (count($strays)>0){
foreach($strays as $id=>$irt){
$root_id = $sub_mids[$irt];
if (!$root_id || $root_id==$id) continue;
$result[$root_id] = array_merge($result[$root_id],$result[$id]);
unset($result[$id]);
}
}
if ($clock) $clock->register('data prepped');
if ($debug) print_r($roots);
//print_r($result);
return $result;
}
function iil_SortThreads(&$tree, $index, $sort_order='ASC'){
if (!is_array($tree) || !is_array($index)) return false;
//create an id to position lookup table
$i = 0;
foreach($index as $id=>$val){
$i++;
$index[$id] = $i;
}
$max = $i+1;
//for each tree, set array key to position
$itree = array();
foreach($tree as $id=>$node){
if (count($tree[$id])<=1){
//for "threads" with only one message, key is position of that message
$n = $index[$id];
$itree[$n] = array($n=>$id);
}else{
//for "threads" with multiple messages,
$min = $max;
$new_a = array();
foreach($tree[$id] as $mid){
$new_a[$index[$mid]] = $mid; //create new sub-array mapping position to id
$pos = $index[$mid];
if ($pos&&$pos<$min) $min = $index[$mid]; //find smallest position
}
$n = $min; //smallest position of child is thread position
//assign smallest position to root level key
//set children array to one created above
ksort($new_a);
$itree[$n] = $new_a;
}
}
//sort by key, this basically sorts all threads
ksort($itree);
$i=0;
$out=array();
foreach($itree as $k=>$node){
$out[$i] = $itree[$k];
$i++;
}
//return
return $out;
}
function iil_IndexThreads(&$tree){
/* creates array mapping mid to thread id */
if (!is_array($tree)) return false;
$t_index = array();
foreach($tree as $pos=>$kids){
foreach($kids as $kid) $t_index[$kid] = $pos;
}
return $t_index;
}
function iil_C_FetchHeaders(&$conn, $mailbox, $message_set){
global $IMAP_USE_INTERNAL_DATE;
$c=0;
$result=array();
$fp = $conn->fp;
if (empty($message_set)) return array();
/* Do "SELECT" command */
if (!iil_C_Select($conn, $mailbox)){
$conn->error = "Couldn't select $mailbox";
return false;
}
/* Get cached records where possible */
if ($conn->do_cache){
$uids = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, "UID");
if (is_array($uids) && count($conn->cache[$mailbox]>0)){
$needed_set = "";
while(list($id,$uid)=each($uids)){
if ($conn->cache[$mailbox][$uid]){
$result[$id] = $conn->cache[$mailbox][$uid];
$result[$id]->id = $id;
}else $needed_set.=($needed_set?",":"").$id;
}
//echo "<!-- iil_C_FetchHeader\nMessage Set: $message_set\nNeeded Set:$needed_set\n//-->\n";
if ($needed_set) $message_set = iil_CompressMessageSet($needed_set);
else return $result;
}
}
/* FETCH date,from,subject headers */
$key="fh".($c++);
$request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS (DATE FROM TO SUBJECT REPLY-TO IN-REPLY-TO CC BCC CONTENT-TRANSFER-ENCODING CONTENT-TYPE MESSAGE-ID REFERENCE)])\r\n";
if (!fputs($fp, $request)) return false;
do{
$line=chop(iil_ReadLine($fp, 200));
$a=explode(" ", $line);
if (($line[0]=="*") && ($a[2]=="FETCH")){
$id=$a[1];
$result[$id]=new iilBasicHeader;
$result[$id]->id = $id;
$result[$id]->subject = "";
/*
Start parsing headers. The problem is, some header "lines" take up multiple lines.
So, we'll read ahead, and if the one we're reading now is a valid header, we'll
process the previous line. Otherwise, we'll keep adding the strings until we come
to the next valid header line.
*/
$i = 0;
$lines = array();
do{
$line = chop(iil_ReadLine($fp, 300),"\r\n");
if (ord($line[0])<=32) $lines[$i].=(empty($lines[$i])?"":"\n").trim(chop($line));
else{
$i++;
$lines[$i] = trim(chop($line));
}
}while($line[0]!=")" && strncmp($line, $key, strlen($key))); // patch from "Maksim Rubis" <siburny@hotmail.com>
if(strncmp($line, $key, strlen($key)))
{
//process header, fill iilBasicHeader obj.
// initialize
if (is_array($headers)){
reset($headers);
while ( list($k, $bar) = each($headers) ) $headers[$k] = "";
}
// create array with header field:data
$headers = array();
while ( list($lines_key, $str) = each($lines) ){
list($field, $string) = iil_SplitHeaderLine($str);
$field = strtolower($field);
$headers[$field] = $string;
}
$result[$id]->date = $headers["date"];
$result[$id]->timestamp = iil_StrToTime($headers["date"]);
$result[$id]->from = $headers["from"];
$result[$id]->to = str_replace("\n", " ", $headers["to"]);
$result[$id]->subject = str_replace("\n", "", $headers["subject"]);
$result[$id]->replyto = str_replace("\n", " ", $headers["reply-to"]);
$result[$id]->cc = str_replace("\n", " ", $headers["cc"]);
$result[$id]->bcc = str_replace("\n", " ", $headers["bcc"]);
$result[$id]->encoding = str_replace("\n", " ", $headers["content-transfer-encoding"]);
$result[$id]->ctype = str_replace("\n", " ", $headers["content-type"]);
$result[$id]->in_reply_to = ereg_replace("[\n<>]",'', $headers['in-reply-to']);
$result[$id]->reference = $headers["reference"];
list($result[$id]->ctype, $ctype_add) = explode(";", $headers["content-type"]);
if (preg_match('/charset="?([a-z0-9\-]+)"?/i', $ctype_add, $regs))
$result[$id]->charset = $regs[1];
$messageID = $headers["message-id"];
if (!$messageID) "mid:".$id;
$result[$id]->messageID = $messageID;
}
else {
$a=explode(" ", $line);
}
}
}while(strcmp($a[0], $key)!=0);
/*
FETCH uid, size, flags
Sample reply line: "* 3 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen \Deleted))"
*/
$command_key="fh".($c++);
$request= $command_key." FETCH $message_set (UID RFC822.SIZE FLAGS INTERNALDATE)\r\n";
if (!fputs($fp, $request)) return false;
do{
$line=chop(iil_ReadLine($fp, 200));
//$a = explode(" ", $line);
//if (($line[0]=="*") && ($a[2]=="FETCH")){
if ($line[0]=="*"){
//echo "<!-- $line //-->\n";
//get outter most parens
$open_pos = strpos($line, "(") + 1;
$close_pos = strrpos($line, ")");
if ($open_pos && $close_pos){
//extract ID from pre-paren
$pre_str = substr($line, 0, $open_pos);
$pre_a = explode(" ", $line);
$id = $pre_a[1];
//get data
$len = $close_pos - $open_pos;
$str = substr($line, $open_pos, $len);
//swap parents with quotes, then explode
$str = eregi_replace("[()]", "\"", $str);
$a = iil_ExplodeQuotedString(" ", $str);
//did we get the right number of replies?
$parts_count = count($a);
if ($parts_count>=8){
for ($i=0;$i<$parts_count;$i=$i+2){
if (strcasecmp($a[$i],"UID")==0) $result[$id]->uid=$a[$i+1];
else if (strcasecmp($a[$i],"RFC822.SIZE")==0) $result[$id]->size=$a[$i+1];
else if (strcasecmp($a[$i],"INTERNALDATE")==0) $time_str = $a[$i+1];
else if (strcasecmp($a[$i],"FLAGS")==0) $flags_str = $a[$i+1];
}
// process flags
$flags_str = eregi_replace('[\\\"]', "", $flags_str);
$flags_a = explode(" ", $flags_str);
//echo "<!-- ID: $id FLAGS: ".implode(",", $flags_a)." //-->\n";
$result[$id]->seen = false;
$result[$id]->recent = false;
$result[$id]->deleted = false;
$result[$id]->answered = false;
if (is_array($flags_a)){
reset($flags_a);
while (list($key,$val)=each($flags_a)){
if (strcasecmp($val,"Seen")==0) $result[$id]->seen = true;
else if (strcasecmp($val, "Deleted")==0) $result[$id]->deleted=true;
else if (strcasecmp($val, "Recent")==0) $result[$id]->recent = true;
else if (strcasecmp($val, "Answered")==0) $result[$id]->answered = true;
}
$result[$id]->flags=$flags_str;
}
// if time is gmt...
$time_str = str_replace('GMT','+0000',$time_str);
//get timezone
$time_str = substr($time_str, 0, -1);
$time_zone_str = substr($time_str, -5); //extract timezone
$time_str = substr($time_str, 1, -6); //remove quotes
$time_zone = (float)substr($time_zone_str, 1, 2); //get first two digits
if ($time_zone_str[3]!='0') $time_zone += 0.5; //handle half hour offset
if ($time_zone_str[0]=="-") $time_zone = $time_zone * -1.0; //minus?
$result[$id]->internaldate = $time_str;
if ($IMAP_USE_INTERNAL_DATE){
//calculate timestamp
$timestamp = strtotime($time_str); //return's server's time
$na_timestamp = $timestamp;
$timestamp -= $time_zone * 3600; //compensate for tz, get GMT
$result[$id]->timestamp = $timestamp;
}
if ($conn->do_cache){
$uid = $result[$id]->uid;
$conn->cache[$mailbox][$uid] = $result[$id];
$conn->cache_dirty[$mailbox] = true;
}
//echo "<!-- ID: $id : $time_str -- local: $na_timestamp (".date("F j, Y, g:i a", $na_timestamp).") tz: $time_zone -- GMT: ".$timestamp." (".date("F j, Y, g:i a", $timestamp).") //-->\n";
}else{
//echo "<!-- ERROR: $id : $str //-->\n";
}
}
}
}while(strpos($line, $command_key)===false);
return $result;
}
function iil_C_FetchHeader(&$conn, $mailbox, $id){
$fp = $conn->fp;
$a=iil_C_FetchHeaders($conn, $mailbox, $id);
if (is_array($a)) return $a[$id];
else return false;
}
function iil_SortHeaders($a, $field, $flag){
if (empty($field)) $field="uid";
$field=strtolower($field);
if ($field=="date"||$field=='internaldate') $field="timestamp";
if (empty($flag)) $flag="ASC";
$flag=strtoupper($flag);
$stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ',"\"") : array("\"");
$c=count($a);
if ($c>0){
/*
Strategy:
First, we'll create an "index" array.
Then, we'll use sort() on that array,
and use that to sort the main array.
*/
// create "index" array
$index=array();
reset($a);
while (list($key, $val)=each($a)){
if ($field=="timestamp"){
$data = @strtotime($val->date);
if ($data == false)
$data = $val->timestamp;
}
else {
$data = $val->$field;
if (is_string($data))
$data=strtoupper(str_replace($stripArr, "", $data));
}
$index[$key]=$data;
}
// sort index
$i=0;
if ($flag=="ASC") asort($index);
else arsort($index);
// form new array based on index
$result=array();
reset($index);
while (list($key, $val)=each($index)){
$result[$key]=$a[$key];
$i++;
}
}
return $result;
}
function iil_C_Expunge(&$conn, $mailbox){
$fp = $conn->fp;
if (iil_C_Select($conn, $mailbox)){
$c=0;
fputs($fp, "exp1 EXPUNGE\r\n");
do{
$line=chop(iil_ReadLine($fp, 100));
if ($line[0]=="*") $c++;
}while (!iil_StartsWith($line, "exp1"));
if (iil_ParseResult($line) == 0){
$conn->selected = ""; //state has changed, need to reselect
//$conn->exists-=$c;
return $c;
}else{
$conn->error = $line;
return -1;
}
}
return -1;
}
function iil_C_ModFlag(&$conn, $mailbox, $messages, $flag, $mod){
if ($mod!="+" && $mod!="-") return -1;
$fp = $conn->fp;
$flags=array(
"SEEN"=>"\\Seen",
"DELETED"=>"\\Deleted",
"RECENT"=>"\\Recent",
"ANSWERED"=>"\\Answered",
"DRAFT"=>"\\Draft",
"FLAGGED"=>"\\Flagged"
);
$flag=strtoupper($flag);
$flag=$flags[$flag];
if (iil_C_Select($conn, $mailbox)){
$c=0;
fputs($fp, "flg STORE $messages ".$mod."FLAGS (".$flag.")\r\n");
do{
$line=chop(iil_ReadLine($fp, 100));
if ($line[0]=="*") $c++;
}while (!iil_StartsWith($line, "flg"));
if (iil_ParseResult($line) == 0){
iil_C_ExpireCachedItems($conn, $mailbox, $messages);
return $c;
}else{
$conn->error = $line;
return -1;
}
}else{
$conn->error = "Select failed";
return -1;
}
}
function iil_C_Flag(&$conn, $mailbox, $messages, $flag){
return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "+");
}
function iil_C_Unflag(&$conn, $mailbox, $messages, $flag){
return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "-");
}
function iil_C_Delete(&$conn, $mailbox, $messages){
return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "+");
}
function iil_C_Undelete(&$conn, $mailbox, $messages){
return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "-");
}
function iil_C_Unseen(&$conn, $mailbox, $messages){
return iil_C_ModFlag($conn, $mailbox, $messages, "SEEN", "-");
}
function iil_C_Copy(&$conn, $messages, $from, $to){
$fp = $conn->fp;
if (empty($from) || empty($to)) return -1;
if (iil_C_Select($conn, $from)){
$c=0;
fputs($fp, "cpy1 COPY $messages \"$to\"\r\n");
$line=iil_ReadReply($fp);
return iil_ParseResult($line);
}else{
return -1;
}
}
function iil_FormatSearchDate($month, $day, $year){
$month = (int)$month;
$months=array(
1=>"Jan", 2=>"Feb", 3=>"Mar", 4=>"Apr",
5=>"May", 6=>"Jun", 7=>"Jul", 8=>"Aug",
9=>"Sep", 10=>"Oct", 11=>"Nov", 12=>"Dec"
);
return $day."-".$months[$month]."-".$year;
}
function iil_C_CountUnseen(&$conn, $folder){
$index = iil_C_Search($conn, $folder, "ALL UNSEEN");
if (is_array($index)){
$str = implode(",", $index);
if (empty($str)) return false;
else return count($index);
}else return false;
}
function iil_C_UID2ID(&$conn, $folder, $uid){
if ($uid > 0){
$id_a = iil_C_Search($conn, $folder, "UID $uid");
if (is_array($id_a)){
$count = count($id_a);
if ($count > 1) return false;
else return $id_a[0];
}
}
return false;
}
function iil_C_ID2UID(&$conn, $folder, $id){
$fp = $conn->fp;
$result=-1;
if ($id > 0) {
if (iil_C_Select($conn, $folder)){
$key = "FUID";
if (fputs($fp, "$key FETCH $id (UID)\r\n")){
do{
$line=chop(iil_ReadLine($fp, 1024));
if (eregi("^\* $id FETCH \(UID (.*)\)", $line, $r)){
$result = $r[1];
}
} while (!preg_match("/^$key/", $line));
}
}
}
return $result;
}
function iil_C_Search(&$conn, $folder, $criteria){
$fp = $conn->fp;
if (iil_C_Select($conn, $folder)){
$c=0;
$query = "srch1 SEARCH ".chop($criteria)."\r\n";
fputs($fp, $query);
do{
$line=trim(chop(iil_ReadLine($fp, 10000)));
if (eregi("^\* SEARCH", $line)){
$str = trim(substr($line, 8));
$messages = explode(" ", $str);
}
}while(!iil_StartsWith($line, "srch1"));
$result_code=iil_ParseResult($line);
if ($result_code==0) return $messages;
else{
$conn->error = "iil_C_Search: ".$line."\n";
return false;
}
}else{
$conn->error = "iil_C_Search: Couldn't select \"$folder\"\n";
return false;
}
}
function iil_C_Move(&$conn, $messages, $from, $to){
$fp = $conn->fp;
if (!$from || !$to) return -1;
$r=iil_C_Copy($conn, $messages, $from,$to);
if ($r==0){
return iil_C_Delete($conn, $from, $messages);
}else{
return $r;
}
}
function iil_C_GetHierarchyDelimiter(&$conn){
if ($conn->delimiter) return $conn->delimiter;
$fp = $conn->fp;
$delimiter = false;
//try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
if (!fputs($fp, "ghd LIST \"\" \"\"\r\n")) return false;
do{
$line=iil_ReadLine($fp, 500);
if ($line[0]=="*"){
$line = rtrim($line);
$a=iil_ExplodeQuotedString(" ", $line);
if ($a[0]=="*") $delimiter = str_replace("\"", "", $a[count($a)-2]);
}
}while (!iil_StartsWith($line, "ghd"));
if (strlen($delimiter)>0) return $delimiter;
//if that fails, try namespace extension
//try to fetch namespace data
fputs($conn->fp, "ns1 NAMESPACE\r\n");
do{
$line = iil_ReadLine($conn->fp, 1024);
if (iil_StartsWith($line, "* NAMESPACE")){
$i = 0;
$data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
}
}while(!iil_StartsWith($line, "ns1"));
if (!is_array($data)) return false;
//extract user space data (opposed to global/shared space)
$user_space_data = $data[0];
if (!is_array($user_space_data)) return false;
//get first element
$first_userspace = $user_space_data[0];
if (!is_array($first_userspace)) return false;
//extract delimiter
$delimiter = $first_userspace[1];
return $delimiter;
}
function iil_C_ListMailboxes(&$conn, $ref, $mailbox){
global $IGNORE_FOLDERS;
$ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
$fp = $conn->fp;
if (empty($mailbox)) $mailbox="*";
if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
// send command
if (!fputs($fp, "lmb LIST \"".$ref."\" \"$mailbox\"\r\n")) return false;
$i=0;
// get folder list
do{
$line=iil_ReadLine($fp, 500);
$line=iil_MultLine($fp, $line);
$a = explode(" ", $line);
if (($line[0]=="*") && ($a[1]=="LIST")){
$line = rtrim($line);
// split one line
$a=iil_ExplodeQuotedString(" ", $line);
// last string is folder name
$folder = str_replace("\"", "", $a[count($a)-1]);
if (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder))) $folders[$i] = $folder;
// second from last is delimiter
$delim = str_replace("\"", "", $a[count($a)-2]);
// is it a container?
$i++;
}
}while (!iil_StartsWith($line, "lmb"));
if (is_array($folders)){
if (!empty($ref)){
// if rootdir was specified, make sure it's the first element
// some IMAP servers (i.e. Courier) won't return it
if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
if ($folders[0]!=$ref) array_unshift($folders, $ref);
}
return $folders;
}else if (iil_ParseResult($line)==0){
return array('INBOX');
}else{
$conn->error = $line;
return false;
}
}
function iil_C_ListSubscribed(&$conn, $ref, $mailbox){
global $IGNORE_FOLDERS;
$ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
$fp = $conn->fp;
if (empty($mailbox)) $mailbox = "*";
if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
$folders = array();
// send command
if (!fputs($fp, "lsb LSUB \"".$ref."\" \"".$mailbox."\"\r\n")){
$conn->error = "Couldn't send LSUB command\n";
return false;
}
$i=0;
// get folder list
do{
$line=iil_ReadLine($fp, 500);
$line=iil_MultLine($fp, $line);
$a = explode(" ", $line);
if (($line[0]=="*") && ($a[1]=="LSUB")){
$line = rtrim($line);
// split one line
$a=iil_ExplodeQuotedString(" ", $line);
// last string is folder name
//$folder = UTF7DecodeString(str_replace("\"", "", $a[count($a)-1]));
$folder = str_replace("\"", "", $a[count($a)-1]);
if ((!in_array($folder, $folders)) && (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder)))) $folders[$i] = $folder;
// second from last is delimiter
$delim = str_replace("\"", "", $a[count($a)-2]);
// is it a container?
$i++;
}
}while (!iil_StartsWith($line, "lsb"));
if (is_array($folders)){
if (!empty($ref)){
// if rootdir was specified, make sure it's the first element
// some IMAP servers (i.e. Courier) won't return it
if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
if ($folders[0]!=$ref) array_unshift($folders, $ref);
}
return $folders;
}else{
$conn->error = $line;
return false;
}
}
function iil_C_Subscribe(&$conn, $folder){
$fp = $conn->fp;
$query = "sub1 SUBSCRIBE \"".$folder."\"\r\n";
fputs($fp, $query);
$line=trim(chop(iil_ReadLine($fp, 10000)));
return iil_ParseResult($line);
}
function iil_C_UnSubscribe(&$conn, $folder){
$fp = $conn->fp;
$query = "usub1 UNSUBSCRIBE \"".$folder."\"\r\n";
fputs($fp, $query);
$line=trim(chop(iil_ReadLine($fp, 10000)));
return iil_ParseResult($line);
}
function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part){
$fp = $conn->fp;
$result=false;
if (($part==0)||(empty($part))) $part="HEADER";
else $part.=".MIME";
if (iil_C_Select($conn, $mailbox)){
$key="fh".($c++);
$request=$key." FETCH $id (BODY.PEEK[$part])\r\n";
if (!fputs($fp, $request)) return false;
do{
$line=chop(iil_ReadLine($fp, 200));
$a=explode(" ", $line);
if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[strlen($line)-1]!=")")){
$line=iil_ReadLine($fp, 300);
while(chop($line)!=")"){
$result.=$line;
$line=iil_ReadLine($fp, 300);
}
}
}while(strcmp($a[0], $key)!=0);
}
return $result;
}
function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode){
/* modes:
1: return string
2: print
3: base64 and print
*/
$fp = $conn->fp;
$result=false;
if (($part==0)||(empty($part))) $part="TEXT";
if (iil_C_Select($conn, $mailbox)){
$reply_key="* ".$id;
// format request
$key="ftch".($c++)." ";
$request=$key."FETCH $id (BODY.PEEK[$part])\r\n";
// send request
if (!fputs($fp, $request)) return false;
// receive reply line
do{
$line = chop(iil_ReadLine($fp, 1000));
$a = explode(" ", $line);
}while ($a[2]!="FETCH");
$len = strlen($line);
if ($line[$len-1] == ")"){
//one line response, get everything between first and last quotes
$from = strpos($line, "\"") + 1;
$to = strrpos($line, "\"");
$len = $to - $from;
if ($mode==1) $result = substr($line, $from, $len);
else if ($mode==2) echo substr($line, $from, $len);
else if ($mode==3) echo base64_decode(substr($line, $from, $len));
}else if ($line[$len-1] == "}"){
//multi-line request, find sizes of content and receive that many bytes
$from = strpos($line, "{") + 1;
$to = strrpos($line, "}");
$len = $to - $from;
$sizeStr = substr($line, $from, $len);
$bytes = (int)$sizeStr;
$received = 0;
while ($received < $bytes){
$remaining = $bytes - $received;
$line = iil_ReadLine($fp, 1024);
$len = strlen($line);
if ($len > $remaining) substr($line, 0, $remaining);
$received += strlen($line);
if ($mode==1) $result .= chop($line)."\n";
else if ($mode==2){ echo chop($line)."\n"; flush(); }
else if ($mode==3){ echo base64_decode($line); flush(); }
}
}
// read in anything up until 'til last line
do{
$line = iil_ReadLine($fp, 1024);
}while(!iil_StartsWith($line, $key));
if ($result){
$result = chop($result);
return $result; // substr($result, 0, strlen($result)-1);
}else return false;
}else{
echo "Select failed.";
}
if ($mode==1) return $result;
else return $received;
}
function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part){
return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
}
function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part){
iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
}
function iil_C_PrintBase64Body(&$conn, $mailbox, $id, $part){
iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
}
function iil_C_CreateFolder(&$conn, $folder){
$fp = $conn->fp;
if (fputs($fp, "c CREATE \"".$folder."\"\r\n")){
do{
$line=iil_ReadLine($fp, 300);
}while($line[0]!="c");
$conn->error = $line;
return (iil_ParseResult($line)==0);
}else{
return false;
}
}
function iil_C_RenameFolder(&$conn, $from, $to){
$fp = $conn->fp;
if (fputs($fp, "r RENAME \"".$from."\" \"".$to."\"\r\n")){
do{
$line=iil_ReadLine($fp, 300);
}while($line[0]!="r");
return (iil_ParseResult($line)==0);
}else{
return false;
}
}
function iil_C_DeleteFolder(&$conn, $folder){
$fp = $conn->fp;
if (fputs($fp, "d DELETE \"".$folder."\"\r\n")){
do{
$line=iil_ReadLine($fp, 300);
}while($line[0]!="d");
return (iil_ParseResult($line)==0);
}else{
$conn->error = "Couldn't send command\n";
return false;
}
}
function iil_C_Append(&$conn, $folder, &$message){
if (!$folder) return false;
$fp = $conn->fp;
$message = str_replace("\r", "", $message);
$message = str_replace("\n", "\r\n", $message);
$len = strlen($message);
if (!$len) return false;
$request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
if (fputs($fp, $request)){
$line=iil_ReadLine($fp, 100);
$sent = fwrite($fp, $message."\r\n");
flush();
do{
$line=iil_ReadLine($fp, 1000);
}while($line[0]!="A");
$result = (iil_ParseResult($line)==0);
if (!$result) $conn->error .= $line."\n";
return $result;
}else{
$conn->error .= "Couldn't send command \"$request\"\n";
return false;
}
}
function iil_C_AppendFromFile(&$conn, $folder, $path){
if (!$folder) return false;
//open message file
$in_fp = false;
if (file_exists(realpath($path))) $in_fp = fopen($path, "r");
if (!$in_fp){
$conn->error .= "Couldn't open $path for reading\n";
return false;
}
$fp = $conn->fp;
$len = filesize($path);
if (!$len) return false;
//send APPEND command
$request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
$bytes_sent = 0;
if (fputs($fp, $request)){
$line=iil_ReadLine($fp, 100);
//send file
while(!feof($in_fp)){
$buffer = fgets($in_fp, 4096);
$bytes_sent += strlen($buffer);
fputs($fp, $buffer);
}
fclose($in_fp);
fputs($fp, "\r\n");
//read response
do{
$line=iil_ReadLine($fp, 1000);
}while($line[0]!="A");
$result = (iil_ParseResult($line)==0);
if (!$result) $conn->error .= $line."\n";
return $result;
}else{
$conn->error .= "Couldn't send command \"$request\"\n";
return false;
}
}
function iil_C_FetchStructureString(&$conn, $folder, $id){
$fp = $conn->fp;
$result=false;
if (iil_C_Select($conn, $folder)){
$key = "F1247";
if (fputs($fp, "$key FETCH $id (BODYSTRUCTURE)\r\n")){
do{
$line=chop(iil_ReadLine($fp, 5000));
if ($line[0]=="*"){
if (ereg("\}$", $line)){
preg_match('/(.+)\{([0-9]+)\}/', $line, $match);
$result = $match[1];
do{
$line = chop(iil_ReadLine($fp, 100));
if (!preg_match("/^$key/", $line)) $result .= $line;
else $done = true;
}while(!$done);
}else{
$result = $line;
}
list($pre, $post) = explode("BODYSTRUCTURE ", $result);
$result = substr($post, 0, strlen($post)-1); //truncate last ')' and return
}
}while (!preg_match("/^$key/",$line));
}
}
return $result;
}
function iil_C_PrintSource(&$conn, $folder, $id, $part){
$header = iil_C_FetchPartHeader($conn, $folder, $id, $part);
//echo str_replace("\r", "", $header);
echo $header;
echo iil_C_PrintPartBody($conn, $folder, $id, $part);
}
function iil_C_GetQuota(&$conn){
/*
b GETQUOTAROOT "INBOX"
* QUOTAROOT INBOX user/rchijiiwa1
* QUOTA user/rchijiiwa1 (STORAGE 654 9765)
b OK Completed
*/
$fp = $conn->fp;
$result=false;
$quota_line = "";
//get line containing quota info
if (fputs($fp, "QUOT1 GETQUOTAROOT \"INBOX\"\r\n")){
do{
$line=chop(iil_ReadLine($fp, 5000));
if (iil_StartsWith($line, "* QUOTA ")) $quota_line = $line;
}while(!iil_StartsWith($line, "QUOT1"));
}
//return false if not found, parse if found
if (!empty($quota_line)){
$quota_line = eregi_replace("[()]", "", $quota_line);
$parts = explode(" ", $quota_line);
$storage_part = array_search("STORAGE", $parts);
if ($storage_part>0){
$result = array();
$used = $parts[$storage_part+1];
$total = $parts[$storage_part+2];
$result["used"] = $used;
$result["total"] = (empty($total)?"??":$total);
$result["percent"] = (empty($total)?"??":round(($used/$total)*100));
$result["free"] = 100 - $result["percent"];
}
}
return $result;
}
function iil_C_ClearFolder(&$conn, $folder){
$num_in_trash = iil_C_CountMessages($conn, $folder);
if ($num_in_trash > 0) iil_C_Delete($conn, $folder, "1:".$num_in_trash);
return (iil_C_Expunge($conn, $folder) >= 0);
}
-?>
\ No newline at end of file
+?>
diff --git a/program/localization/fr/labels.inc b/program/localization/fr/labels.inc
index 2fb2d6e83..9362ed7e5 100644
--- a/program/localization/fr/labels.inc
+++ b/program/localization/fr/labels.inc
@@ -1,206 +1,206 @@
<?php
/*
+-----------------------------------------------------------------------+
| language/fr/labels.inc |
| |
| Language file of the RoundCube Webmail client |
| Copyright (C) 2005, RoundQube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
+-----------------------------------------------------------------------+
| Author: aldweb <info@aldweb.com>, Pierre HAEGELI <pierre@haegeli.net> |
+-----------------------------------------------------------------------+
$Id$
*/
$labels = array();
// login page
$labels['welcome'] = 'Bienvenue à $product';
$labels['username'] = 'ID utilisateur';
$labels['password'] = 'Mot de passe';
$labels['server'] = 'Serveur';
$labels['login'] = 'Connexion';
// taskbar
$labels['logout'] = 'Quitter';
$labels['mail'] = 'e-Mail';
$labels['settings'] = 'Préférences';
$labels['addressbook'] = 'Carnet d\'adresses';
// mailbox names
$labels['inbox'] = 'Boîte de réception';
$labels['drafts'] = 'Ébauches';
$labels['sent'] = 'Messages envoyés';
$labels['trash'] = 'Corbeille';
$labels['drafts'] = 'Brouillons';
$labels['junk'] = 'A trier';
// message listing
$labels['subject'] = 'Objet';
$labels['from'] = 'De';
$labels['to'] = 'A';
$labels['cc'] = 'Cc';
$labels['bcc'] = 'Cci';
$labels['replyto'] = 'Répondre à';
$labels['date'] = 'Date';
$labels['size'] = 'Taille';
$labels['priority'] = 'Priorité';
$labels['organization'] = 'Organisation';
// aliases
$labels['reply-to'] = $labels['replyto'];
$labels['mailboxlist'] = 'Dossiers';
$labels['messagesfromto'] = 'Messages $from à $to sur $count';
$labels['messagenrof'] = 'Message $nr sur $count';
$labels['moveto'] = 'Déplacer vers...';
$labels['download'] = 'Télécharger';
$labels['filename'] = 'Nom du fichier';
$labels['filesize'] = 'Taille du fichier';
$labels['preferhtml'] = 'Préférer HTML';
$labels['htmlmessage'] = 'Message HTML';
$labels['prettydate'] = 'Belles dates';
$labels['addtoaddressbook'] = 'Ajouter au carnet d\'adresses';
// weekdays short
$labels['sun'] = 'Dim';
$labels['mon'] = 'Lun';
$labels['tue'] = 'Mar';
$labels['wed'] = 'Mer';
$labels['thu'] = 'Jeu';
$labels['fri'] = 'Ven';
$labels['sat'] = 'Sam';
// weekdays long
$labels['sunday'] = 'Dimanche';
$labels['monday'] = 'Lundi';
$labels['tuesday'] = 'Mardi';
$labels['wednesday'] = 'Mercredi';
$labels['thursday'] = 'Jeudi';
$labels['friday'] = 'Vendredi';
$labels['saturday'] = 'Samedi';
$labels['today'] = 'Aujourd\'hui';
// toolbar buttons
$labels['checkmail'] = 'Vérification les nouveaux messages';
$labels['writenewmessage'] = 'Créer un nouveau message';
$labels['replytomessage'] = 'Répondre au message';
$labels['replytoallmessage'] = 'Répondre à tous';
$labels['forwardmessage'] = 'Transmettre le message';
$labels['deletemessage'] = 'Déplacer le message dans la corbeille';
$labels['printmessage'] = 'Imprimer ce message';
$labels['previousmessages'] = 'Voir les messages précédents';
$labels['nextmessages'] = 'Voir les messages suivants';
$labels['backtolist'] = 'Retourner à la liste des messages';
$labels['viewsource'] = 'Voir le code source';
$labels['select'] = 'Sélectionner';
$labels['all'] = 'Tous';
$labels['none'] = 'Aucun';
$labels['unread'] = 'Non lus';
-$labels['compact'] = 'Compresser';
+//$labels['compact'] = 'Compresser';
$labels['empty'] = 'Vider';
$labels['purge'] = 'Purger';
$labels['quota'] = 'Utilisation Disque';
// message compose
$labels['compose'] = 'Composer un nouveau message';
$labels['savemessage'] = 'Économiser cette ébauche';
$labels['sendmessage'] = 'Envoyer le message maintenant';
$labels['addattachment'] = 'Joindre un fichier';
$labels['charset'] = 'Encodage';
$labels['attachments'] = 'Fichiers joints';
$labels['upload'] = 'Joindre';
$labels['close'] = 'Fermer';
$labels['low'] = 'Basse';
$labels['lowest'] = 'La plus basse';
$labels['normal'] = 'Normale';
$labels['high'] = 'Elevée';
$labels['highest'] = 'La plus élevée';
$labels['nosubject'] = '(pas de sujet)';
$labels['showimages'] = 'Montrer les images';
// address boook
$labels['name'] = 'Nom à afficher';
$labels['firstname'] = 'Prénom';
$labels['surname'] = 'Nom';
$labels['email'] = 'e-Mail';
$labels['addcontact'] = 'Ajouter un nouveau contact';
$labels['editcontact'] = 'Editer le contact';
$labels['edit'] = 'Editer';
$labels['cancel'] = 'Annuler';
$labels['save'] = 'Sauvegarder';
$labels['delete'] = 'Supprimer';
$labels['newcontact'] = 'Créer un nouveau contact';
$labels['addcontact'] = 'Ajouter le contact sélectionné à votre Carnet d\'adresses';
$labels['deletecontact'] = 'Supprimer les contacts sélectionnés';
$labels['composeto'] = 'Ecrire un message à';
$labels['contactsfromto'] = 'Contacts $from à $to sur $count';
$labels['print'] = 'Imprimer';
$labels['export'] = 'Exporter';
// LDAP search
$labels['ldapsearch'] = 'Recherche dans répertoires LDAP';
$labels['ldappublicsearchname'] = 'Nom du contact';
$labels['ldappublicsearchtype'] = 'Correspondance exacte ?';
$labels['ldappublicserverselect'] = 'Sélectionnez les serveurs';
$labels['ldappublicsearchfield'] = 'Recherche sur';
$labels['ldappublicsearchform'] = 'Chercher un contact';
$labels['ldappublicsearch'] = 'Recherche';
// settings
$labels['settingsfor'] = 'Paramètres pour';
$labels['preferences'] = 'Préférences';
$labels['userpreferences'] = 'Préférences utilisateur';
$labels['editpreferences'] = 'Editer les préférences utilisateur';
$labels['identities'] = 'Identités';
$labels['manageidentities'] = 'Gérer les identités pour ce compte';
$labels['newidentity'] = 'Nouvelle identité';
$labels['newitem'] = 'Nouvel élément';
$labels['edititem'] = 'Editer l\'élément';
$labels['setdefault'] = 'Paramètres par défaut';
$labels['language'] = 'Langue';
$labels['timezone'] = 'Fuseau horaire';
$labels['pagesize'] = 'Nombre de lignes par page';
$labels['signature'] = 'Signature';
$labels['folder'] = 'Dossier';
$labels['folders'] = 'Dossiers';
$labels['foldername'] = 'Nom du dossier';
$labels['subscribed'] = 'Abonné';
$labels['create'] = 'Créer';
$labels['createfolder'] = 'Créer un nouveau dossier';
$labels['deletefolder'] = 'Supprimer le dossier';
$labels['managefolders'] = 'Gérer les dossiers';
$labels['sortby'] = 'Trier par';
$labels['sortasc'] = 'Tri ascendant';
$labels['sortdesc'] = 'Tri descendant';
-?>
\ No newline at end of file
+?>
diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc
index e51cbf867..f949eb232 100644
--- a/program/steps/mail/check_recent.inc
+++ b/program/steps/mail/check_recent.inc
@@ -1,56 +1,56 @@
<?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, in all mailboxes |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id: check_recent.inc 233 2006-06-26 17:31:20Z richs $
*/
$REMOTE_REQUEST = TRUE;
$a_mailboxes = $IMAP->list_mailboxes();
foreach ($a_mailboxes as $mbox_name)
{
if ($mbox_name == $IMAP->get_mailbox_name())
{
if ($recent_count = $IMAP->messagecount(NULL, 'RECENT', TRUE))
{
$count = $IMAP->messagecount();
$unread_count = $IMAP->messagecount(NULL, 'UNSEEN', TRUE);
- $commands .= sprintf("this.set_unread_count('%s', %d, true);\n", addslashes($mbox_name), $unread_count);
+ $commands .= sprintf("this.set_unread_count('%s', %d);\n", addslashes($mbox_name), $unread_count);
$commands .= sprintf("this.set_env('messagecount', %d);\n", $count);
$commands .= sprintf("this.set_rowcount('%s');\n", rcmail_get_messagecount_text());
$commands .= sprintf("this.set_quota('%s');\n", $IMAP->get_quota());
// 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);
}
}
else
{
if ($IMAP->messagecount($mbox_name, 'RECENT'))
$commands .= sprintf("this.set_unread_count('%s', %d);\n", addslashes($mbox_name), $IMAP->messagecount($mbox_name, 'UNSEEN'));
}
}
rcube_remote_response($commands);
?>
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 7e2b3b28d..266c16336 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1,1490 +1,1492 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/func.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Provide webmail functionality and GUI objects |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
require_once('lib/html2text.inc');
require_once('lib/enriched.inc');
$EMAIL_ADDRESS_PATTERN = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/i';
if (empty($_SESSION['mbox'])){
$_SESSION['mbox'] = $IMAP->get_mailbox_name();
}
// set imap properties and session vars
if (strlen($_GET['_mbox']))
{
$IMAP->set_mailbox($_GET['_mbox']);
$_SESSION['mbox'] = $_GET['_mbox'];
}
if (strlen($_GET['_page']))
{
$IMAP->set_page($_GET['_page']);
$_SESSION['page'] = $_GET['_page'];
}
// set mailbox to INBOX if not set
if (empty($_SESSION['mbox']))
$_SESSION['mbox'] = $IMAP->get_mailbox_name();
// set default sort col/order to session
if (!isset($_SESSION['sort_col']))
$_SESSION['sort_col'] = $CONFIG['message_sort_col'];
if (!isset($_SESSION['sort_order']))
$_SESSION['sort_order'] = $CONFIG['message_sort_order'];
// define url for getting message parts
if (strlen($_GET['_uid']))
$GET_URL = sprintf('%s&_action=get&_mbox=%s&_uid=%d', $COMM_PATH, $IMAP->get_mailbox_name(), $_GET['_uid']);
// set current mailbox in client environment
$OUTPUT->add_script(sprintf("%s.set_env('mailbox', '%s');", $JS_OBJECT_NAME, $IMAP->get_mailbox_name()));
if ($CONFIG['trash_mbox'])
$OUTPUT->add_script(sprintf("%s.set_env('trash_mailbox', '%s');", $JS_OBJECT_NAME, $CONFIG['trash_mbox']));
if ($CONFIG['drafts_mbox'])
$OUTPUT->add_script(sprintf("%s.set_env('drafts_mailbox', '%s');", $JS_OBJECT_NAME, $CONFIG['drafts_mbox']));
// return the mailboxlist in HTML
function rcmail_mailbox_list($attrib)
{
global $IMAP, $CONFIG, $OUTPUT, $JS_OBJECT_NAME, $COMM_PATH;
static $s_added_script = FALSE;
static $a_mailboxes;
// add some labels to client
rcube_add_label('purgefolderconfirm');
// $mboxlist_start = rcube_timer();
$type = $attrib['type'] ? $attrib['type'] : 'ul';
$add_attrib = $type=='select' ? array('style', 'class', 'id', 'name', 'onchange') :
array('style', 'class', 'id');
if ($type=='ul' && !$attrib['id'])
$attrib['id'] = 'rcmboxlist';
// allow the following attributes to be added to the <ul> tag
$attrib_str = create_attrib_string($attrib, $add_attrib);
$out = '<' . $type . $attrib_str . ">\n";
// add no-selection option
if ($type=='select' && $attrib['noselection'])
$out .= sprintf('<option value="0">%s</option>'."\n",
rcube_label($attrib['noselection']));
// get mailbox list
$mbox_name = $IMAP->get_mailbox_name();
// for these mailboxes we have localized labels
$special_mailboxes = array('inbox', 'sent', 'drafts', 'trash', 'junk');
// build the folders tree
if (empty($a_mailboxes))
{
// get mailbox list
$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);
}
// var_dump($a_mailboxes);
if ($type=='select')
$out .= rcmail_render_folder_tree_select($a_mailboxes, $special_mailboxes, $mbox_name, $attrib['maxlength']);
else
$out .= rcmail_render_folder_tree_html($a_mailboxes, $special_mailboxes, $mbox_name, $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']));
return $out . "</$type>";
}
// create a hierarchical array of the mailbox list
function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='')
{
$pos = strpos($folder, $delm);
if ($pos !== false)
{
$subFolders = substr($folder, $pos+1);
$currentFolder = substr($folder, 0, $pos);
}
else
{
$subFolders = false;
$currentFolder = $folder;
}
$path .= $currentFolder;
if (!isset($arrFolders[$currentFolder]))
{
$arrFolders[$currentFolder] = array('id' => $path,
'name' => rcube_charset_convert($currentFolder, 'UTF-7'),
'folders' => array());
}
if (!empty($subFolders))
rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm);
}
// return html for a structured list <ul> for the mailbox tree
function rcmail_render_folder_tree_html(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0)
{
global $JS_OBJECT_NAME, $COMM_PATH, $IMAP, $CONFIG, $OUTPUT;
$idx = 0;
$out = '';
foreach ($arrFolders as $key => $folder)
{
$zebra_class = ($nestLevel*$idx)%2 ? 'even' : 'odd';
$title = '';
$folder_lc = strtolower($folder['id']);
if (in_array($folder_lc, $special))
$foldername = rcube_label($folder_lc);
else
{
$foldername = $folder['name'];
// shorten the folder name to a given length
if ($maxlength && $maxlength>1)
{
$fname = abbrevate_string($foldername, $maxlength);
if ($fname != $foldername)
$title = ' title="'.rep_specialchars_output($foldername, 'html', 'all').'"';
$foldername = $fname;
}
}
// add unread message count display
if ($unread_count = $IMAP->messagecount($folder['id'], 'RECENT', ($folder['id']==$mbox_name)))
$foldername .= sprintf(' (%d)', $unread_count);
// make folder name safe for ids and class names
$folder_css = $class_name = preg_replace('/[^a-z0-9\-_]/', '', $folder_lc);
// set special class for Sent, Drafts, Trash and Junk
if ($folder['id']==$CONFIG['sent_mbox'])
$class_name = 'sent';
else if ($folder['id']==$CONFIG['drafts_mbox'])
$class_name = 'drafts';
else if ($folder['id']==$CONFIG['trash_mbox'])
$class_name = 'trash';
else if ($folder['id']==$CONFIG['junk_mbox'])
$class_name = 'junk';
$out .= sprintf('<li id="rcmbx%s" class="mailbox %s %s%s%s"><a href="%s&_mbox=%s"'.
' onclick="return %s.command(\'list\',\'%s\')"'.
' onmouseup="return %s.mbox_mouse_up(\'%s\')"%s>%s</a>',
$folder_css,
$class_name,
$zebra_class,
$unread_count ? ' unread' : '',
addslashes($folder['id'])==addslashes($mbox_name) ? ' selected' : '',
$COMM_PATH,
urlencode($folder['id']),
$JS_OBJECT_NAME,
addslashes($folder['id']),
$JS_OBJECT_NAME,
addslashes($folder['id']),
$title,
rep_specialchars_output($foldername, 'html', 'all'));
if (!empty($folder['folders']))
$out .= "\n<ul>\n" . rcmail_render_folder_tree_html($folder['folders'], $special, $mbox_name, $maxlength, $nestLevel+1) . "</ul>\n";
$out .= "</li>\n";
$idx++;
}
return $out;
}
// return html for a flat list <select> for the mailbox tree
function rcmail_render_folder_tree_select(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0)
{
global $IMAP, $OUTPUT;
$idx = 0;
$out = '';
foreach ($arrFolders as $key=>$folder)
{
$folder_lc = strtolower($folder['id']);
if (in_array($folder_lc, $special))
$foldername = rcube_label($folder_lc);
else
{
$foldername = $folder['name'];
// shorten the folder name to a given length
if ($maxlength && $maxlength>1)
$foldername = abbrevate_string($foldername, $maxlength);
}
$out .= sprintf('<option value="%s">%s%s</option>'."\n",
$folder['id'],
str_repeat('&nbsp;', $nestLevel*4),
rep_specialchars_output($foldername, 'html', 'all'));
if (!empty($folder['folders']))
$out .= rcmail_render_folder_tree_select($folder['folders'], $special, $mbox_name, $maxlength, $nestLevel+1);
$idx++;
}
return $out;
}
// return the message list as HTML table
function rcmail_message_list($attrib)
{
global $IMAP, $CONFIG, $COMM_PATH, $OUTPUT, $JS_OBJECT_NAME;
$skin_path = $CONFIG['skin_path'];
$image_tag = '<img src="%s%s" alt="%s" border="0" />';
// check to see if we have some settings for sorting
$sort_col = $_SESSION['sort_col'];
$sort_order = $_SESSION['sort_order'];
// get message headers
$a_headers = $IMAP->list_headers('', '', $sort_col, $sort_order);
// add id to message list table if not specified
if (!strlen($attrib['id']))
$attrib['id'] = 'rcubemessagelist';
// allow the following attributes to be added to the <table> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
$out = '<table' . $attrib_str . ">\n";
// define list of cols to be displayed
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
$a_sort_cols = array('subject', 'date', 'from', 'to', 'size');
// show 'to' instead of from in sent messages
if (($IMAP->get_mailbox_name()==$CONFIG['sent_mbox'] || $IMAP->get_mailbox_name()==$CONFIG['drafts_mbox']) && ($f = array_search('from', $a_show_cols))
&& !array_search('to', $a_show_cols))
$a_show_cols[$f] = 'to';
// add col definition
$out .= '<colgroup>';
$out .= '<col class="icon" />';
foreach ($a_show_cols as $col)
$out .= sprintf('<col class="%s" />', $col);
$out .= '<col class="icon" />';
$out .= "</colgroup>\n";
// add table title
$out .= "<thead><tr>\n<td class=\"icon\">&nbsp;</td>\n";
$javascript = '';
foreach ($a_show_cols as $col)
{
// get column name
$col_name = rep_specialchars_output(rcube_label($col));
// make sort links
$sort = '';
if ($IMAP->get_capability('sort') && in_array($col, $a_sort_cols))
{
// have buttons configured
if (!empty($attrib['sortdescbutton']) || !empty($attrib['sortascbutton']))
{
$sort = '&nbsp;&nbsp;';
// asc link
if (!empty($attrib['sortascbutton']))
{
$sort .= rcube_button(array('command' => 'sort',
'prop' => $col.'_ASC',
'image' => $attrib['sortascbutton'],
'align' => 'absmiddle',
'title' => 'sortasc'));
}
// desc link
if (!empty($attrib['sortdescbutton']))
{
$sort .= rcube_button(array('command' => 'sort',
'prop' => $col.'_DESC',
'image' => $attrib['sortdescbutton'],
'align' => 'absmiddle',
'title' => 'sortdesc'));
}
}
// just add a link tag to the header
else
{
$col_name = sprintf('<a href="./#sort" onclick="return %s.command(\'sort\',\'%s\',this)" title="%s">%s</a>',
$JS_OBJECT_NAME,
$col,
rcube_label('sortby'),
$col_name);
}
}
$sort_class = $col==$sort_col ? " sorted$sort_order" : '';
// put it all together
$out .= '<td class="'.$col.$sort_class.'" id="rcmHead'.$col.'">' . "$col_name$sort</td>\n";
}
$out .= '<td class="icon">'.($attrib['attachmenticon'] ? sprintf($image_tag, $skin_path, $attrib['attachmenticon'], '') : '')."</td>\n";
$out .= "</tr></thead>\n<tbody>\n";
// no messages in this mailbox
if (!sizeof($a_headers))
{
$out .= rep_specialchars_output(
sprintf('<tr><td colspan="%d">%s</td></tr>',
sizeof($a_show_cols)+2,
rcube_label('nomessagesfound')));
}
$a_js_message_arr = array();
// create row for each message
foreach ($a_headers as $i => $header) //while (list($i, $header) = each($a_headers))
{
$message_icon = $attach_icon = '';
$js_row_arr = array();
$zebra_class = $i%2 ? 'even' : 'odd';
// set messag attributes to javascript array
if ($header->deleted)
$js_row_arr['deleted'] = true;
if (!$header->seen)
$js_row_arr['unread'] = true;
if ($header->answered)
$js_row_arr['replied'] = true;
// set message icon
if ($attrib['deletedicon'] && $header->deleted)
$message_icon = $attrib['deletedicon'];
else if ($attrib['unreadicon'] && !$header->seen)
$message_icon = $attrib['unreadicon'];
else if ($attrib['repliedicon'] && $header->answered)
$message_icon = $attrib['repliedicon'];
else if ($attrib['messageicon'])
$message_icon = $attrib['messageicon'];
// set attachment icon
if ($attrib['attachmenticon'] && preg_match("/multipart\/m/i", $header->ctype))
$attach_icon = $attrib['attachmenticon'];
$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
foreach ($a_show_cols as $col)
{
if ($col=='from' || $col=='to')
$cont = rep_specialchars_output(rcmail_address_string($header->$col, 3, $attrib['addicon']));
else if ($col=='subject')
$cont = rep_specialchars_output($IMAP->decode_header($header->$col), 'html', 'all');
else if ($col=='size')
$cont = show_bytes($header->$col);
else if ($col=='date')
$cont = format_date($header->date); //date('m.d.Y G:i:s', strtotime($header->date));
else
$cont = rep_specialchars_output($header->$col, 'html', 'all');
$out .= '<td class="'.$col.'">' . $cont . "</td>\n";
}
$out .= sprintf("<td class=\"icon\">%s</td>\n", $attach_icon ? sprintf($image_tag, $skin_path, $attach_icon, '') : '');
$out .= "</tr>\n";
if (sizeof($js_row_arr))
$a_js_message_arr[$header->uid] = $js_row_arr;
}
// complete message table
$out .= "</tbody></table>\n";
$message_count = $IMAP->messagecount();
// set client env
$javascript .= sprintf("%s.gui_object('mailcontframe', '%s');\n", $JS_OBJECT_NAME, 'mailcontframe');
$javascript .= sprintf("%s.gui_object('messagelist', '%s');\n", $JS_OBJECT_NAME, $attrib['id']);
$javascript .= sprintf("%s.set_env('messagecount', %d);\n", $JS_OBJECT_NAME, $message_count);
$javascript .= sprintf("%s.set_env('current_page', %d);\n", $JS_OBJECT_NAME, $IMAP->list_page);
$javascript .= sprintf("%s.set_env('pagecount', %d);\n", $JS_OBJECT_NAME, ceil($message_count/$IMAP->page_size));
$javascript .= sprintf("%s.set_env('sort_col', '%s');\n", $JS_OBJECT_NAME, $sort_col);
$javascript .= sprintf("%s.set_env('sort_order', '%s');\n", $JS_OBJECT_NAME, $sort_order);
if ($attrib['messageicon'])
$javascript .= sprintf("%s.set_env('messageicon', '%s%s');\n", $JS_OBJECT_NAME, $skin_path, $attrib['messageicon']);
if ($attrib['deletedicon'])
$javascript .= sprintf("%s.set_env('deletedicon', '%s%s');\n", $JS_OBJECT_NAME, $skin_path, $attrib['deletedicon']);
if ($attrib['unreadicon'])
$javascript .= sprintf("%s.set_env('unreadicon', '%s%s');\n", $JS_OBJECT_NAME, $skin_path, $attrib['unreadicon']);
if ($attrib['repliedicon'])
$javascript .= sprintf("%s.set_env('repliedicon', '%s%s');\n", $JS_OBJECT_NAME, $skin_path, $attrib['repliedicon']);
if ($attrib['attachmenticon'])
$javascript .= sprintf("%s.set_env('attachmenticon', '%s%s');\n", $JS_OBJECT_NAME, $skin_path, $attrib['attachmenticon']);
$javascript .= sprintf("%s.set_env('messages', %s);", $JS_OBJECT_NAME, array2js($a_js_message_arr));
$OUTPUT->add_script($javascript);
return $out;
}
// return javascript commands to add rows to the message list
function rcmail_js_message_list($a_headers, $insert_top=FALSE)
{
global $CONFIG, $IMAP;
$commands = '';
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
// show 'to' instead of from in sent messages
if (strtolower($IMAP->get_mailbox_name())=='sent' && ($f = array_search('from', $a_show_cols))
&& !array_search('to', $a_show_cols))
$a_show_cols[$f] = 'to';
+ $commands .= sprintf("this.set_message_coltypes(%s);\n", array2js($a_show_cols));
+
// loop through message headers
for ($n=0; $a_headers[$n]; $n++)
{
$header = $a_headers[$n];
$a_msg_cols = array();
$a_msg_flags = array();
// format each col; similar as in rcmail_message_list()
foreach ($a_show_cols as $col)
{
if ($col=='from' || $col=='to')
$cont = rep_specialchars_output(rcmail_address_string($header->$col, 3));
else if ($col=='subject')
$cont = rep_specialchars_output($IMAP->decode_header($header->$col), 'html', 'all');
else if ($col=='size')
$cont = show_bytes($header->$col);
else if ($col=='date')
$cont = format_date($header->date); //date('m.d.Y G:i:s', strtotime($header->date));
else
$cont = rep_specialchars_output($header->$col, 'html', 'all');
$a_msg_cols[$col] = $cont;
}
$a_msg_flags['deleted'] = $header->deleted ? 1 : 0;
$a_msg_flags['unread'] = $header->seen ? 0 : 1;
$a_msg_flags['replied'] = $header->answered ? 1 : 0;
$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),
$insert_top);
}
return $commands;
}
// return code for search function
function rcmail_search_form($attrib)
{
global $OUTPUT, $JS_OBJECT_NAME;
// add some labels to client
rcube_add_label('searching');
$attrib['name'] = '_q';
if (empty($attrib['id']))
$attrib['id'] = 'rcmqsearchbox';
$input_q = new textfield($attrib);
$out = $input_q->show();
$OUTPUT->add_script(sprintf("%s.gui_object('qsearchbox', '%s');",
$JS_OBJECT_NAME,
$attrib['id']));
// add form tag around text field
if (empty($attrib['form']))
$out = sprintf('<form name="rcmqsearchform" action="./" '.
'onsubmit="%s.command(\'search\');return false" style="display:inline;">%s</form>',
$JS_OBJECT_NAME,
$out);
return $out;
}
function rcmail_messagecount_display($attrib)
{
global $IMAP, $OUTPUT, $JS_OBJECT_NAME;
if (!$attrib['id'])
$attrib['id'] = 'rcmcountdisplay';
$OUTPUT->add_script(sprintf("%s.gui_object('countdisplay', '%s');",
$JS_OBJECT_NAME,
$attrib['id']));
// allow the following attributes to be added to the <span> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
$out = '<span' . $attrib_str . '>';
$out .= rcmail_get_messagecount_text();
$out .= '</span>';
return $out;
}
function rcmail_quota_display($attrib)
{
global $IMAP, $OUTPUT, $JS_OBJECT_NAME;
if (!$attrib['id'])
$attrib['id'] = 'rcmquotadisplay';
$OUTPUT->add_script(sprintf("%s.gui_object('quotadisplay', '%s');", $JS_OBJECT_NAME, $attrib['id']));
// allow the following attributes to be added to the <span> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
if (!$IMAP->get_capability('QUOTA'))
$quota_text = rcube_label('unknown');
else if (!($quota_text = $IMAP->get_quota()))
$quota_text = rcube_label('unlimited');
$out = '<span' . $attrib_str . '>';
$out .= $quota_text;
$out .= '</span>';
return $out;
}
function rcmail_get_messagecount_text($count=NULL, $page=NULL)
{
global $IMAP, $MESSAGE;
if (isset($MESSAGE['index']))
{
return rcube_label(array('name' => 'messagenrof',
'vars' => array('nr' => $MESSAGE['index']+1,
'count' => $count!==NULL ? $count : $IMAP->messagecount())));
}
if ($page===NULL)
$page = $IMAP->list_page;
$start_msg = ($page-1) * $IMAP->page_size + 1;
$max = $count!==NULL ? $count : $IMAP->messagecount();
if ($max==0)
$out = rcube_label('mailboxempty');
else
$out = rcube_label(array('name' => 'messagesfromto',
'vars' => array('from' => $start_msg,
'to' => min($max, $start_msg + $IMAP->page_size - 1),
'count' => $max)));
return rep_specialchars_output($out);
}
function rcmail_print_body($part, $safe=FALSE, $plain=FALSE) // $body, $ctype_primary='text', $ctype_secondary='plain', $encoding='7bit', $safe=FALSE, $plain=FALSE)
{
global $IMAP, $REMOTE_OBJECTS, $JS_OBJECT_NAME;
// extract part properties: body, ctype_primary, ctype_secondary, encoding, parameters
extract($part);
$block = $plain ? '%s' : '%s'; //'<div style="display:block;">%s</div>';
$body = $IMAP->mime_decode($body, $encoding);
$body = $IMAP->charset_decode($body, $parameters);
// text/html
if ($ctype_secondary=='html')
{
if (!$safe) // remove remote images and scripts
{
$remote_patterns = array('/(src|background)=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
// '/(src|background)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Ui',
'/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
'/(<link.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
'/url\s*\(["\']?([hftps]{3,5}:\/{2}[^"\'\s]+)["\']?\)/i',
'/url\s*\(["\']?([\.\/]+[^"\'\s]+)["\']?\)/i',
'/<script.+<\/script>/Umis');
$remote_replaces = array('', // '\\1=\\2#\\4',
// '\\1=\\2#\\4',
'',
'', // '\\1#\\3',
'none',
'none',
'');
// set flag if message containes remote obejcts that where blocked
foreach ($remote_patterns as $pattern)
{
if (preg_match($pattern, $body))
{
$REMOTE_OBJECTS = TRUE;
break;
}
}
$body = preg_replace($remote_patterns, $remote_replaces, $body);
}
return sprintf($block, rep_specialchars_output($body, 'html', '', FALSE));
}
// text/enriched
if ($ctype_secondary=='enriched')
{
$body = enriched_to_html($body);
return sprintf($block, rep_specialchars_output($body, 'html'));
}
else
{
// make links and email-addresses clickable
$convert_patterns = $convert_replaces = $replace_strings = array();
$url_chars = 'a-z0-9_\-\+\*\$\/&%=@#:';
$url_chars_within = '\?\.~,!';
$convert_patterns[] = "/([\w]+):\/\/([a-z0-9\-\.]+[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
$convert_replaces[] = "rcmail_str_replacement('<a href=\"\\1://\\2\" target=\"_blank\">\\1://\\2</a>', \$replace_strings)";
$convert_patterns[] = "/([^\/:]|\s)(www\.)([a-z0-9\-]{2,}[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
$convert_replaces[] = "rcmail_str_replacement('\\1<a href=\"http://\\2\\3\" target=\"_blank\">\\2\\3</a>', \$replace_strings)";
$convert_patterns[] = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/ie';
$convert_replaces[] = "rcmail_str_replacement('<a href=\"mailto:\\1\" onclick=\"return $JS_OBJECT_NAME.command(\'compose\',\'\\1\',this)\">\\1</a>', \$replace_strings)";
$body = wordwrap(trim($body), 80);
$body = preg_replace($convert_patterns, $convert_replaces, $body);
// split body into single lines
$a_lines = preg_split('/\r?\n/', $body);
// colorize quoted parts
for($n=0; $n<sizeof($a_lines); $n++)
{
$line = $a_lines[$n];
if ($line{2}=='>')
$color = 'red';
else if ($line{1}=='>')
$color = 'green';
else if ($line{0}=='>')
$color = 'blue';
else
$color = FALSE;
$line = rep_specialchars_output($line, 'html', 'replace', FALSE);
if ($color)
$a_lines[$n] = sprintf('<font color="%s">%s</font>', $color, $line);
else
$a_lines[$n] = $line;
}
// insert the links for urls and mailtos
$body = preg_replace("/##string_replacement\{([0-9]+)\}##/e", "\$replace_strings[\\1]", join("\n", $a_lines));
return sprintf($block, "<pre>\n".$body."\n</pre>");
}
}
// add a string to the replacement array and return a replacement string
function rcmail_str_replacement($str, &$rep)
{
static $count = 0;
$rep[$count] = stripslashes($str);
return "##string_replacement{".($count++)."}##";
}
function rcmail_parse_message($structure, $arg=array(), $recursive=FALSE)
{
global $IMAP;
static $sa_inline_objects = array();
// arguments are: (bool)$prefer_html, (string)$get_url
extract($arg);
$a_attachments = array();
$a_return_parts = array();
$out = '';
$message_ctype_primary = strtolower($structure->ctype_primary);
$message_ctype_secondary = strtolower($structure->ctype_secondary);
// show message headers
if ($recursive && is_array($structure->headers) && isset($structure->headers['subject']))
$a_return_parts[] = array('type' => 'headers',
'headers' => $structure->headers);
// print body if message doesn't have multiple parts
if ($message_ctype_primary=='text')
{
$a_return_parts[] = array('type' => 'content',
'body' => $structure->body,
'ctype_primary' => $message_ctype_primary,
'ctype_secondary' => $message_ctype_secondary,
'parameters' => $structure->ctype_parameters,
'encoding' => $structure->headers['content-transfer-encoding']);
}
// message contains alternative parts
else if ($message_ctype_primary=='multipart' && $message_ctype_secondary=='alternative' && is_array($structure->parts))
{
// get html/plaintext parts
$plain_part = $html_part = $print_part = $related_part = NULL;
foreach ($structure->parts as $p => $sub_part)
{
$sub_ctype_primary = strtolower($sub_part->ctype_primary);
$sub_ctype_secondary = strtolower($sub_part->ctype_secondary);
// check if sub part is
if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='plain')
$plain_part = $p;
else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='html')
$html_part = $p;
else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='enriched')
$enriched_part = $p;
else if ($sub_ctype_primary=='multipart' && $sub_ctype_secondary=='related')
$related_part = $p;
}
// parse related part (alternative part could be in here)
if ($related_part!==NULL && $prefer_html)
{
list($parts, $attachmnts) = rcmail_parse_message($structure->parts[$related_part], $arg, TRUE);
$a_return_parts = array_merge($a_return_parts, $parts);
$a_attachments = array_merge($a_attachments, $attachmnts);
}
// print html/plain part
else if ($html_part!==NULL && $prefer_html)
$print_part = $structure->parts[$html_part];
else if ($enriched_part!==NULL)
$print_part = $structure->parts[$enriched_part];
else if ($plain_part!==NULL)
$print_part = $structure->parts[$plain_part];
// show message body
if (is_object($print_part))
$a_return_parts[] = array('type' => 'content',
'body' => $print_part->body,
'ctype_primary' => strtolower($print_part->ctype_primary),
'ctype_secondary' => strtolower($print_part->ctype_secondary),
'parameters' => $print_part->ctype_parameters,
'encoding' => $print_part->headers['content-transfer-encoding']);
// show plaintext warning
else if ($html_part!==NULL)
$a_return_parts[] = array('type' => 'content',
'body' => rcube_label('htmlmessage'),
'ctype_primary' => 'text',
'ctype_secondary' => 'plain');
// add html part as attachment
if ($html_part!==NULL && $structure->parts[$html_part]!==$print_part)
{
$html_part = $structure->parts[$html_part];
$a_attachments[] = array('filename' => rcube_label('htmlmessage'),
'encoding' => $html_part->headers['content-transfer-encoding'],
'mimetype' => 'text/html',
'part_id' => $html_part->mime_id,
'size' => strlen($IMAP->mime_decode($html_part->body, $html_part->headers['content-transfer-encoding'])));
}
}
// message contains multiple parts
else if ($message_ctype_primary=='multipart' && is_array($structure->parts))
{
foreach ($structure->parts as $mail_part)
{
$primary_type = strtolower($mail_part->ctype_primary);
$secondary_type = strtolower($mail_part->ctype_secondary);
// multipart/alternative
if ($primary_type=='multipart') // && ($secondary_type=='alternative' || $secondary_type=='mixed' || $secondary_type=='related'))
{
list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE);
$a_return_parts = array_merge($a_return_parts, $parts);
$a_attachments = array_merge($a_attachments, $attachmnts);
}
// part text/[plain|html] OR message/delivery-status
else if (($primary_type=='text' && ($secondary_type=='plain' || $secondary_type=='html') && $mail_part->disposition!='attachment') ||
($primary_type=='message' && $secondary_type=='delivery-status'))
{
$a_return_parts[] = array('type' => 'content',
'body' => $mail_part->body,
'ctype_primary' => $primary_type,
'ctype_secondary' => $secondary_type,
'parameters' => $mail_part->ctype_parameters,
'encoding' => $mail_part->headers['content-transfer-encoding']);
}
// part message/*
else if ($primary_type=='message')
{
/* don't parse headers here; they're parsed within the recursive call to rcmail_parse_message()
if ($mail_part->parts[0]->headers)
$a_return_parts[] = array('type' => 'headers',
'headers' => $mail_part->parts[0]->headers);
*/
list($parts, $attachmnts) = rcmail_parse_message($mail_part->parts[0], $arg, TRUE);
$a_return_parts = array_merge($a_return_parts, $parts);
$a_attachments = array_merge($a_attachments, $attachmnts);
}
// part is file/attachment
else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] ||
(empty($mail_part->disposition) && ($mail_part->d_parameters['filename'] || $mail_part->ctype_parameters['name'])))
{
if ($message_ctype_secondary=='related' && $mail_part->headers['content-id'])
$sa_inline_objects[] = array('filename' => rcube_imap::decode_mime_string($mail_part->d_parameters['filename']),
'mimetype' => strtolower("$primary_type/$secondary_type"),
'part_id' => $mail_part->mime_id,
'content_id' => preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']));
else if ($mail_part->d_parameters['filename'])
$a_attachments[] = array('filename' => rcube_imap::decode_mime_string($mail_part->d_parameters['filename']),
'encoding' => strtolower($mail_part->headers['content-transfer-encoding']),
'mimetype' => strtolower("$primary_type/$secondary_type"),
'part_id' => $mail_part->mime_id,
'size' => strlen($IMAP->mime_decode($mail_part->body, $mail_part->headers['content-transfer-encoding'])) /*,
'content' => $mail_part->body */);
else if ($mail_part->ctype_parameters['name'])
$a_attachments[] = array('filename' => rcube_imap::decode_mime_string($mail_part->ctype_parameters['name']),
'encoding' => strtolower($mail_part->headers['content-transfer-encoding']),
'mimetype' => strtolower("$primary_type/$secondary_type"),
'part_id' => $mail_part->mime_id,
'size' => strlen($IMAP->mime_decode($mail_part->body, $mail_part->headers['content-transfer-encoding'])) /*,
'content' => $mail_part->body */);
else if ($mail_part->headers['content-description'])
$a_attachments[] = array('filename' => rcube_imap::decode_mime_string($mail_part->headers['content-description']),
'encoding' => strtolower($mail_part->headers['content-transfer-encoding']),
'mimetype' => strtolower("$primary_type/$secondary_type"),
'part_id' => $mail_part->mime_id,
'size' => strlen($IMAP->mime_decode($mail_part->body, $mail_part->headers['content-transfer-encoding'])) /*,
'content' => $mail_part->body */);
}
}
// if this was a related part try to resolve references
if ($message_ctype_secondary=='related' && sizeof($sa_inline_objects))
{
$a_replace_patters = array();
$a_replace_strings = array();
foreach ($sa_inline_objects as $inline_object)
{
$a_replace_patters[] = 'cid:'.$inline_object['content_id'];
$a_replace_strings[] = sprintf($get_url, $inline_object['part_id']);
}
foreach ($a_return_parts as $i => $return_part)
{
if ($return_part['type']!='content')
continue;
// decode body and replace cid:...
$a_return_parts[$i]['body'] = str_replace($a_replace_patters, $a_replace_strings, $IMAP->mime_decode($return_part['body'], $return_part['encoding']));
$a_return_parts[$i]['encoding'] = '7bit';
}
}
}
// join all parts together
//$out .= join($part_delimiter, $a_return_parts);
return array($a_return_parts, $a_attachments);
}
// return table with message headers
function rcmail_message_headers($attrib, $headers=NULL)
{
global $IMAP, $OUTPUT, $MESSAGE;
static $sa_attrib;
// keep header table attrib
if (is_array($attrib) && !$sa_attrib)
$sa_attrib = $attrib;
else if (!is_array($attrib) && is_array($sa_attrib))
$attrib = $sa_attrib;
if (!isset($MESSAGE))
return FALSE;
// get associative array of headers object
if (!$headers)
$headers = is_object($MESSAGE['headers']) ? get_object_vars($MESSAGE['headers']) : $MESSAGE['headers'];
$header_count = 0;
// allow the following attributes to be added to the <table> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
$out = '<table' . $attrib_str . ">\n";
// show these headers
$standard_headers = array('subject', 'from', 'organization', 'to', 'cc', 'bcc', 'reply-to', 'date');
foreach ($standard_headers as $hkey)
{
if (!$headers[$hkey])
continue;
if ($hkey=='date' && !empty($headers[$hkey]))
$header_value = format_date(strtotime($headers[$hkey]));
else if (in_array($hkey, array('from', 'to', 'cc', 'bcc', 'reply-to')))
$header_value = rep_specialchars_output(rcmail_address_string($IMAP->decode_header($headers[$hkey]), NULL, $attrib['addicon']));
else
$header_value = rep_specialchars_output($IMAP->decode_header($headers[$hkey]), '', 'all');
$out .= "\n<tr>\n";
$out .= '<td class="header-title">'.rep_specialchars_output(rcube_label($hkey)).":&nbsp;</td>\n";
$out .= '<td class="'.$hkey.'" width="90%">'.$header_value."</td>\n</tr>";
$header_count++;
}
$out .= "\n</table>\n\n";
return $header_count ? $out : '';
}
function rcmail_message_body($attrib)
{
global $CONFIG, $OUTPUT, $MESSAGE, $GET_URL, $REMOTE_OBJECTS, $JS_OBJECT_NAME;
if (!is_array($MESSAGE['parts']) && !$MESSAGE['body'])
return '';
if (!$attrib['id'])
$attrib['id'] = 'rcmailMsgBody';
$safe_mode = (bool)$_GET['_safe'];
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
$out = '<div '. $attrib_str . ">\n";
$header_attrib = array();
foreach ($attrib as $attr => $value)
if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs))
$header_attrib[$regs[1]] = $value;
// this is an ecrypted message
// -> create a plaintext body with the according message
if (!sizeof($MESSAGE['parts']) && $MESSAGE['headers']->ctype=='multipart/encrypted')
{
$MESSAGE['parts'][0] = array('type' => 'content',
'ctype_primary' => 'text',
'ctype_secondary' => 'plain',
'body' => rcube_label('encryptedmessage'));
}
if ($MESSAGE['parts'])
{
foreach ($MESSAGE['parts'] as $i => $part)
{
if ($part['type']=='headers')
$out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part['headers']);
else if ($part['type']=='content')
{
if (empty($part['parameters']) || empty($part['parameters']['charset']))
$part['parameters']['charset'] = $MESSAGE['headers']->charset;
// $body = rcmail_print_body($part['body'], $part['ctype_primary'], $part['ctype_secondary'], $part['encoding'], $safe_mode);
$body = rcmail_print_body($part, $safe_mode);
$out .= '<div class="message-part">';
if ($part['ctype_secondary']!='plain')
$out .= rcmail_mod_html_body($body, $attrib['id']);
else
$out .= $body;
$out .= "</div>\n";
}
}
}
else
$out .= $MESSAGE['body'];
$ctype_primary = strtolower($MESSAGE['structure']->ctype_primary);
$ctype_secondary = strtolower($MESSAGE['structure']->ctype_secondary);
// list images after mail body
if (get_boolean($attrib['showimages']) && $ctype_primary=='multipart' && $ctype_secondary=='mixed' &&
sizeof($MESSAGE['attachments']) && !strstr($message_body, '<html') && strlen($GET_URL))
{
foreach ($MESSAGE['attachments'] as $attach_prop)
{
if (strpos($attach_prop['mimetype'], 'image/')===0)
$out .= sprintf("\n<hr />\n<p align=\"center\"><img src=\"%s&_part=%s\" alt=\"%s\" title=\"%s\" /></p>\n",
$GET_URL, $attach_prop['part_id'],
$attach_prop['filename'],
$attach_prop['filename']);
}
}
// tell client that there are blocked remote objects
if ($REMOTE_OBJECTS && !$safe_mode)
$OUTPUT->add_script(sprintf("%s.set_env('blockedobjects', true);", $JS_OBJECT_NAME));
$out .= "\n</div>";
return $out;
}
// modify a HTML message that it can be displayed inside a HTML page
function rcmail_mod_html_body($body, $container_id)
{
// remove any null-byte characters before parsing
$body = preg_replace('/\x00/', '', $body);
$last_style_pos = 0;
$body_lc = strtolower($body);
// find STYLE tags
while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos)))
{
$pos2 += 8;
$body_pre = substr($body, 0, $pos);
$styles = substr($body, $pos, $pos2-$pos);
$body_post = substr($body, $pos2, strlen($body)-$pos2);
// replace all css definitions with #container [def]
$styles = rcmail_mod_css_styles($styles, $container_id);
$body = $body_pre . $styles . $body_post;
$last_style_pos = $pos2;
}
// remove SCRIPT tags
foreach (array('script', 'applet', 'object', 'embed', 'iframe') as $tag)
{
while (($pos = strpos($body_lc, '<'.$tag)) && ($pos2 = strpos($body_lc, '</'.$tag.'>', $pos)))
{
$pos2 += 8;
$body = substr($body, 0, $pos) . substr($body, $pos2, strlen($body)-$pos2);
$body_lc = strtolower($body);
}
}
// replace event handlers on any object
$body = preg_replace('/\s(on[a-z]+)=/im', ' __removed=', $body);
// resolve <base href>
$base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i';
if (preg_match($base_reg, $body, $regs))
{
$base_url = $regs[2];
$body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body);
$body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body);
$body = preg_replace($base_reg, '', $body);
}
// add comments arround html and other tags
$out = preg_replace(array('/(<\/?html[^>]*>)/i',
'/(<\/?head[^>]*>)/i',
'/(<title[^>]*>.+<\/title>)/ui',
'/(<\/?meta[^>]*>)/i'),
'<!--\\1-->',
$body);
$out = preg_replace(array('/(<body[^>]*>)/i',
'/(<\/body>)/i'),
array('<div class="rcmBody">',
'</div>'),
$out);
return $out;
}
// replace all css definitions with #container [def]
function rcmail_mod_css_styles($source, $container_id)
{
$a_css_values = array();
$last_pos = 0;
// cut out all contents between { and }
while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos)))
{
$key = sizeof($a_css_values);
$a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1));
$source = substr($source, 0, $pos+1) . "<<str_replacement[$key]>>" . substr($source, $pos2, strlen($source)-$pos2);
$last_pos = $pos+2;
}
$styles = preg_replace('/(^\s*|,\s*)([a-z0-9\._][a-z0-9\.\-_]*)/im', "\\1#$container_id \\2", $source);
$styles = preg_replace('/<<str_replacement\[([0-9]+)\]>>/e', "\$a_css_values[\\1]", $styles);
// replace body definition because we also stripped off the <body> tag
$styles = preg_replace("/$container_id\s+body/i", "$container_id div.rcmBody", $styles);
return $styles;
}
// return first text part of a message
function rcmail_first_text_part($message_parts)
{
if (!is_array($message_parts))
return FALSE;
$html_part = NULL;
// check all message parts
foreach ($message_parts as $pid => $part)
{
$mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
if ($mimetype=='text/plain')
{
$body = rcube_imap::mime_decode($part->body, $part->headers['content-transfer-encoding']);
$body = rcube_imap::charset_decode($body, $part->ctype_parameters);
return $body;
}
else if ($mimetype=='text/html')
{
$html_part = rcube_imap::mime_decode($part->body, $part->headers['content-transfer-encoding']);
$html_part = rcube_imap::charset_decode($html_part, $part->ctype_parameters);
}
}
// convert HTML to plain text
if ($html_part)
{
// remove special chars encoding
$trans = array_flip(get_html_translation_table(HTML_ENTITIES));
$html_part = strtr($html_part, $trans);
// create instance of html2text class
$txt = new html2text($html_part);
return $txt->get_text();
}
return FALSE;
}
// get source code of a specific message and cache it
function rcmail_message_source($uid)
{
global $IMAP, $DB, $CONFIG;
// get message ID if uid is given
$cache_key = $IMAP->mailbox.'.msg';
$cached = $IMAP->get_cached_message($cache_key, $uid, FALSE);
// message is cached in database
if ($cached && !empty($cached->body))
return $cached->body;
if (!$cached)
$headers = $IMAP->get_headers($uid);
else
$headers = &$cached;
// create unique identifier based on message_id
if (!empty($headers->messageID))
$message_id = md5($headers->messageID);
else
$message_id = md5($headers->uid.'@'.$_SESSION['imap_host']);
$temp_dir = $CONFIG['temp_dir'].(!eregi('\/$', $CONFIG['temp_dir']) ? '/' : '');
$cache_dir = $temp_dir.$_SESSION['client_id'];
$cache_path = $cache_dir.'/'.$message_id;
// message is cached in temp dir
if ($CONFIG['enable_caching'] && is_dir($cache_dir) && is_file($cache_path))
{
if ($fp = fopen($cache_path, 'r'))
{
$msg_source = fread($fp, filesize($cache_path));
fclose($fp);
return $msg_source;
}
}
// get message from server
$msg_source = $IMAP->get_raw_body($uid);
// return message source without caching
if (!$CONFIG['enable_caching'])
return $msg_source;
// let's cache the message body within the database
if ($cached && ($CONFIG['db_max_length'] -300) > $headers->size)
{
$DB->query("UPDATE ".get_table_name('messages')."
SET body=?
WHERE user_id=?
AND cache_key=?
AND uid=?",
$msg_source,
$_SESSION['user_id'],
$cache_key,
$uid);
return $msg_source;
}
// create dir for caching
if (!is_dir($cache_dir))
$dir = mkdir($cache_dir);
else
$dir = true;
// attempt to write a file with the message body
if ($dir && ($fp = fopen($cache_path, 'w')))
{
fwrite($fp, $msg_source);
fclose($fp);
}
else
{
raise_error(array('code' => 403, 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__,
'message' => "Failed to write to temp dir"), TRUE, FALSE);
}
return $msg_source;
}
// decode address string and re-format it as HTML links
function rcmail_address_string($input, $max=NULL, $addicon=NULL)
{
global $IMAP, $PRINT_MODE, $CONFIG, $OUTPUT, $JS_OBJECT_NAME, $EMAIL_ADDRESS_PATTERN;
$a_parts = $IMAP->decode_address_list($input);
if (!sizeof($a_parts))
return $input;
$c = count($a_parts);
$j = 0;
$out = '';
foreach ($a_parts as $part)
{
$j++;
if ($PRINT_MODE)
$out .= sprintf('%s &lt;%s&gt;', rep_specialchars_output($part['name']), $part['mailto']);
else if (preg_match($EMAIL_ADDRESS_PATTERN, $part['mailto']))
{
$out .= sprintf('<a href="mailto:%s" onclick="return %s.command(\'compose\',\'%s\',this)" class="rcmContactAddress" title="%s">%s</a>',
$part['mailto'],
$JS_OBJECT_NAME,
$part['mailto'],
$part['mailto'],
rep_specialchars_output($part['name']));
if ($addicon)
$out .= sprintf('&nbsp;<a href="#add" onclick="return %s.command(\'add-contact\',\'%s\',this)" title="%s"><img src="%s%s" alt="add" border="0" /></a>',
$JS_OBJECT_NAME,
urlencode($part['string']),
rcube_label('addtoaddressbook'),
$CONFIG['skin_path'],
$addicon);
}
else
{
if ($part['name'])
$out .= rep_specialchars_output($part['name']);
if ($part['mailto'])
$out .= (strlen($out) ? ' ' : '') . sprintf('&lt;%s&gt;', $part['mailto']);
}
if ($c>$j)
$out .= ','.($max ? '&nbsp;' : ' ');
if ($max && $j==$max && $c>$j)
{
$out .= '...';
break;
}
}
return $out;
}
function rcmail_message_part_controls()
{
global $CONFIG, $IMAP, $MESSAGE;
if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$_GET['_part']])
return '';
$part = $MESSAGE['parts'][$_GET['_part']];
$attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary'));
$out = '<table '. $attrib_str . ">\n";
$filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name'];
$filesize = strlen($IMAP->mime_decode($part->body, $part->headers['content-transfer-encoding']));
if ($filename)
{
$out .= sprintf('<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n",
rcube_label('filename'),
rep_specialchars_output($filename),
str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']),
rcube_label('download'));
}
if ($filesize)
$out .= sprintf('<tr><td class="title">%s</td><td>%s</td></tr>'."\n",
rcube_label('filesize'),
show_bytes($filesize));
$out .= "\n</table>";
return $out;
}
function rcmail_message_part_frame($attrib)
{
global $MESSAGE;
$part = $MESSAGE['parts'][$_GET['_part']];
$ctype_primary = strtolower($part->ctype_primary);
$attrib['src'] = './?'.str_replace('_frame=', ($ctype_primary=='text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']);
$attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height'));
$out = '<iframe '. $attrib_str . "></ifame>";
return $out;
}
// create temp dir for attachments
function rcmail_create_compose_tempdir()
{
global $CONFIG;
if ($_SESSION['compose']['temp_dir'])
return $_SESSION['compose']['temp_dir'];
if (!empty($CONFIG['temp_dir']))
$temp_dir = $CONFIG['temp_dir'].(!eregi('\/$', $CONFIG['temp_dir']) ? '/' : '').$_SESSION['compose']['id'];
// create temp-dir for uploaded attachments
if (!empty($CONFIG['temp_dir']) && is_writeable($CONFIG['temp_dir']))
{
mkdir($temp_dir);
$_SESSION['compose']['temp_dir'] = $temp_dir;
}
return $_SESSION['compose']['temp_dir'];
}
// clear message composing settings
function rcmail_compose_cleanup()
{
if (!isset($_SESSION['compose']))
return;
// remove attachment files from temp dir
if (is_array($_SESSION['compose']['attachments']))
foreach ($_SESSION['compose']['attachments'] as $attachment)
@unlink($attachment['path']);
// kill temp dir
if ($_SESSION['compose']['temp_dir'])
@rmdir($_SESSION['compose']['temp_dir']);
unset($_SESSION['compose']);
}
?>

File Metadata

Mime Type
text/x-diff
Expires
Mon, Aug 17, 5:54 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1261542
Default Alt Text
(297 KB)

Event Timeline