| | |
| | | <?php |
| | | |
| | | /* |
| | | /** |
| | | +-----------------------------------------------------------------------+ |
| | | | program/include/rcube_storage.php | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2012, The Roundcube Dev Team | |
| | | | Copyright (C) 2012, Kolab Systems AG | |
| | |
| | | | | |
| | | | PURPOSE: | |
| | | | Mail Storage Engine | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Thomas Bruederli <roundcube@gmail.com> | |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-----------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | |
| | | /** |
| | | * Abstract class for accessing mail messages storage server |
| | |
| | | */ |
| | | public $conn; |
| | | |
| | | /** |
| | | * List of supported special folder types |
| | | * |
| | | * @var array |
| | | */ |
| | | public static $folder_types = array('drafts', 'sent', 'junk', 'trash'); |
| | | |
| | | protected $folder = 'INBOX'; |
| | | protected $default_charset = 'ISO-8859-1'; |
| | | protected $default_folders = array('INBOX'); |
| | | protected $search_set; |
| | | protected $options = array('auth_method' => 'check'); |
| | | protected $options = array('auth_type' => 'check'); |
| | | protected $page_size = 10; |
| | | protected $list_page = 1; |
| | | protected $threading = false; |
| | | |
| | | /** |
| | |
| | | protected $all_headers = array( |
| | | 'IN-REPLY-TO', |
| | | 'BCC', |
| | | 'SENDER', |
| | | 'MESSAGE-ID', |
| | | 'CONTENT-TRANSFER-ENCODING', |
| | | 'REFERENCES', |
| | |
| | | 'MAIL-FOLLOWUP-TO', |
| | | 'MAIL-REPLY-TO', |
| | | 'RETURN-PATH', |
| | | 'DELIVERED-TO', |
| | | ); |
| | | |
| | | const UNKNOWN = 0; |
| | |
| | | */ |
| | | abstract function connect($host, $user, $pass, $port = 143, $use_ssl = null); |
| | | |
| | | |
| | | /** |
| | | * Close connection. Usually done on script shutdown |
| | | */ |
| | | abstract function close(); |
| | | |
| | | |
| | | /** |
| | | * Checks connection state. |
| | |
| | | */ |
| | | abstract function is_connected(); |
| | | |
| | | |
| | | /** |
| | | * Check connection state, connect if not connected. |
| | | * |
| | | * @return bool Connection state. |
| | | */ |
| | | abstract function check_connection(); |
| | | |
| | | |
| | | /** |
| | | * Returns code of last error |
| | |
| | | */ |
| | | abstract function get_error_code(); |
| | | |
| | | |
| | | /** |
| | | * Returns message of last error |
| | | * |
| | |
| | | */ |
| | | abstract function get_error_str(); |
| | | |
| | | |
| | | /** |
| | | * Returns code of last command response |
| | | * |
| | | * @return int Response code (class constant) |
| | | */ |
| | | abstract function get_response_code(); |
| | | |
| | | |
| | | /** |
| | | * Set connection and class options |
| | |
| | | $this->options = array_merge($this->options, (array)$opt); |
| | | } |
| | | |
| | | /** |
| | | * Get connection/class option |
| | | * |
| | | * @param string $name Option name |
| | | * |
| | | * @param mixed Option value |
| | | */ |
| | | public function get_option($name) |
| | | { |
| | | return $this->options[$name]; |
| | | } |
| | | |
| | | /** |
| | | * Activate/deactivate debug mode. |
| | |
| | | * @param boolean $dbg True if conversation with the server should be logged |
| | | */ |
| | | abstract function set_debug($dbg = true); |
| | | |
| | | |
| | | /** |
| | | * Set default message charset. |
| | |
| | | { |
| | | $this->default_charset = $cs; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * This list of folders will be listed above all other folders |
| | | * |
| | | * @param array $arr Indexed list of folder names |
| | | */ |
| | | public function set_default_folders($arr) |
| | | { |
| | | if (is_array($arr)) { |
| | | $this->default_folders = $arr; |
| | | |
| | | // add inbox if not included |
| | | if (!in_array('INBOX', $this->default_folders)) { |
| | | array_unshift($this->default_folders, 'INBOX'); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set internal folder reference. |
| | |
| | | $this->folder = $folder; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the currently used folder name |
| | | * |
| | |
| | | return $this->folder; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set internal list page number. |
| | | * |
| | |
| | | */ |
| | | public function set_page($page) |
| | | { |
| | | $this->list_page = (int) $page; |
| | | if ($page = intval($page)) { |
| | | $this->list_page = $page; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Gets internal list page number. |
| | |
| | | return $this->list_page; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Set internal page size |
| | | * |
| | |
| | | { |
| | | $this->page_size = (int) $size; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Get internal page size |
| | |
| | | return $this->page_size; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Save a search result for future message listing methods. |
| | | * |
| | |
| | | */ |
| | | abstract function set_search_set($set); |
| | | |
| | | |
| | | /** |
| | | * Return the saved search set. |
| | | * |
| | | * @return array Search set in driver specific format, NULL if search wasn't initialized |
| | | */ |
| | | abstract function get_search_set(); |
| | | |
| | | |
| | | /** |
| | | * Returns the storage server's (IMAP) capability |
| | |
| | | * @return mixed Capability value or TRUE if supported, FALSE if not |
| | | */ |
| | | abstract function get_capability($cap); |
| | | |
| | | |
| | | /** |
| | | * Sets threading flag to the best supported THREAD algorithm. |
| | |
| | | return $this->threading; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Get current threading flag. |
| | | * |
| | |
| | | { |
| | | return $this->threading; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Checks the PERMANENTFLAGS capability of the current folder |
| | |
| | | */ |
| | | abstract function check_permflag($flag); |
| | | |
| | | |
| | | /** |
| | | * Returns the delimiter that is used by the server |
| | | * for folder hierarchy separation. |
| | |
| | | * @return string Delimiter string |
| | | */ |
| | | abstract function get_hierarchy_delimiter(); |
| | | |
| | | |
| | | /** |
| | | * Get namespace |
| | |
| | | */ |
| | | abstract function get_namespace($name = null); |
| | | |
| | | |
| | | /** |
| | | * Get messages count for a specific folder. |
| | | * |
| | | * @param string $folder Folder name |
| | | * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] |
| | | * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS] |
| | | * @param boolean $force Force reading from server and update cache |
| | | * @param boolean $status Enables storing folder status info (max UID/count), |
| | | * required for folder_status() |
| | |
| | | */ |
| | | abstract function count($folder = null, $mode = 'ALL', $force = false, $status = true); |
| | | |
| | | /** |
| | | * Public method for listing message flags |
| | | * |
| | | * @param string $folder Folder name |
| | | * @param array $uids Message UIDs |
| | | * @param int $mod_seq Optional MODSEQ value |
| | | * |
| | | * @return array Indexed array with message flags |
| | | */ |
| | | abstract function list_flags($folder, $uids, $mod_seq = null); |
| | | |
| | | /** |
| | | * Public method for listing headers. |
| | |
| | | */ |
| | | abstract function list_messages($folder = null, $page = null, $sort_field = null, $sort_order = null, $slice = 0); |
| | | |
| | | |
| | | /** |
| | | * Return sorted list of message UIDs |
| | | * |
| | |
| | | * @return rcube_result_index|rcube_result_thread List of messages (UIDs) |
| | | */ |
| | | abstract function index($folder = null, $sort_field = null, $sort_order = null); |
| | | |
| | | |
| | | /** |
| | | * Invoke search request to the server. |
| | |
| | | */ |
| | | abstract function search($folder = null, $str = 'ALL', $charset = null, $sort_field = null); |
| | | |
| | | |
| | | /** |
| | | * Direct (real and simple) search request (without result sorting and caching). |
| | | * |
| | |
| | | * @return rcube_result_index Search result (UIDs) |
| | | */ |
| | | abstract function search_once($folder = null, $str = 'ALL'); |
| | | |
| | | |
| | | /** |
| | | * Refresh saved search set |
| | |
| | | |
| | | /** |
| | | * Fetch message headers and body structure from the server and build |
| | | * an object structure similar to the one generated by PEAR::Mail_mimeDecode |
| | | * an object structure. |
| | | * |
| | | * @param int $uid Message UID to fetch |
| | | * @param string $folder Folder to read from |
| | |
| | | * @return object rcube_message_header Message data |
| | | */ |
| | | abstract function get_message($uid, $folder = null); |
| | | |
| | | |
| | | /** |
| | | * Return message headers object of a specific message |
| | |
| | | * @return rcube_message_header Message headers |
| | | */ |
| | | abstract function get_message_headers($uid, $folder = null, $force = false); |
| | | |
| | | |
| | | /** |
| | | * Fetch message body of a specific message from the server |
| | |
| | | * @return string Message/part body if not printed |
| | | */ |
| | | abstract function get_message_part($uid, $part = 1, $o_part = null, $print = null, $fp = null, $skip_charset_conv = false); |
| | | |
| | | |
| | | /** |
| | | * Fetch message body of a specific message from the server |
| | |
| | | $headers->charset ? $headers->charset : $this->default_charset); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the whole message source as string (or saves to a file) |
| | | * |
| | | * @param int $uid Message UID |
| | | * @param resource $fp File pointer to save the message |
| | | * @param int $uid Message UID |
| | | * @param resource $fp File pointer to save the message |
| | | * @param string $part Optional message part ID |
| | | * |
| | | * @return string Message source string |
| | | */ |
| | | abstract function get_raw_body($uid, $fp = null); |
| | | |
| | | abstract function get_raw_body($uid, $fp = null, $part = null); |
| | | |
| | | /** |
| | | * Returns the message headers as string |
| | | * |
| | | * @param int $uid Message UID |
| | | * @param int $uid Message UID |
| | | * @param string $part Optional message part ID |
| | | * |
| | | * @return string Message headers string |
| | | */ |
| | | abstract function get_raw_headers($uid); |
| | | |
| | | abstract function get_raw_headers($uid, $part = null); |
| | | |
| | | /** |
| | | * Sends the whole message source to stdout |
| | |
| | | * @param bool $formatted Enables line-ending formatting |
| | | */ |
| | | abstract function print_raw_body($uid, $formatted = true); |
| | | |
| | | |
| | | /** |
| | | * Set message flag to one or several messages |
| | |
| | | * @return bool Operation status |
| | | */ |
| | | abstract function set_flag($uids, $flag, $folder = null, $skip_cache = false); |
| | | |
| | | |
| | | /** |
| | | * Remove message flag for one or several messages |
| | |
| | | return $this->set_flag($uids, 'UN'.$flag, $folder); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Append a mail message (source) to a specific folder. |
| | | * |
| | | * @param string $folder Target folder |
| | | * @param string $message The message source string or filename |
| | | * @param string $headers Headers string if $message contains only the body |
| | | * @param boolean $is_file True if $message is a filename |
| | | * @param array $flags Message flags |
| | | * @param mixed $date Message internal date |
| | | * @param string $folder Target folder |
| | | * @param string|array $message The message source string or filename |
| | | * or array (of strings and file pointers) |
| | | * @param string $headers Headers string if $message contains only the body |
| | | * @param boolean $is_file True if $message is a filename |
| | | * @param array $flags Message flags |
| | | * @param mixed $date Message internal date |
| | | * |
| | | * @return int|bool Appended message UID or True on success, False on error |
| | | */ |
| | | abstract function save_message($folder, &$message, $headers = '', $is_file = false, $flags = array(), $date = null); |
| | | |
| | | |
| | | /** |
| | | * Move message(s) from one folder to another. |
| | |
| | | */ |
| | | abstract function move_message($uids, $to, $from = null); |
| | | |
| | | |
| | | /** |
| | | * Copy message(s) from one mailbox to another. |
| | | * |
| | |
| | | */ |
| | | abstract function copy_message($uids, $to, $from = null); |
| | | |
| | | |
| | | /** |
| | | * Mark message(s) as deleted and expunge. |
| | | * |
| | |
| | | * @return boolean True on success, False on error |
| | | */ |
| | | abstract function delete_message($uids, $folder = null); |
| | | |
| | | |
| | | /** |
| | | * Expunge message(s) and clear the cache. |
| | |
| | | */ |
| | | abstract function expunge_message($uids, $folder = null, $clear_cache = true); |
| | | |
| | | |
| | | /** |
| | | * Parse message UIDs input |
| | | * |
| | | * @param mixed $uids UIDs array or comma-separated list or '*' or '1:*' |
| | | * @param mixed $uids UIDs array or comma-separated list or '*' or '1:*' |
| | | * |
| | | * @return array Two elements array with UIDs converted to list and ALL flag |
| | | */ |
| | |
| | | else { |
| | | if (is_array($uids)) { |
| | | $uids = join(',', $uids); |
| | | } |
| | | else if (strpos($uids, ':')) { |
| | | $uids = join(',', rcube_imap_generic::uncompressMessageSet($uids)); |
| | | } |
| | | |
| | | if (preg_match('/[^0-9,]/', $uids)) { |
| | |
| | | */ |
| | | abstract function list_folders_subscribed($root = '', $name = '*', $filter = null, $rights = null, $skip_sort = false); |
| | | |
| | | |
| | | /** |
| | | * Get a list of all folders available on the server. |
| | | * |
| | |
| | | */ |
| | | abstract function list_folders($root = '', $name = '*', $filter = null, $rights = null, $skip_sort = false); |
| | | |
| | | |
| | | /** |
| | | * Subscribe to a specific folder(s) |
| | | * |
| | |
| | | */ |
| | | abstract function subscribe($folders); |
| | | |
| | | |
| | | /** |
| | | * Unsubscribe folder(s) |
| | | * |
| | |
| | | * @return boolean True on success |
| | | */ |
| | | abstract function unsubscribe($folders); |
| | | |
| | | |
| | | /** |
| | | * Create a new folder on the server. |
| | |
| | | */ |
| | | abstract function create_folder($folder, $subscribe = false); |
| | | |
| | | |
| | | /** |
| | | * Set a new name to an existing folder |
| | | * |
| | |
| | | */ |
| | | abstract function rename_folder($folder, $new_name); |
| | | |
| | | |
| | | /** |
| | | * Remove a folder from the server. |
| | | * |
| | |
| | | * @return boolean True on success, False on error |
| | | */ |
| | | abstract function delete_folder($folder); |
| | | |
| | | |
| | | /** |
| | | * Send expunge command and clear the cache. |
| | |
| | | return $this->expunge_message('*', $folder, $clear_cache); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Remove all messages in a folder.. |
| | | * |
| | |
| | | return $this->delete_message('*', $folder); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Checks if folder exists and is subscribed |
| | | * |
| | |
| | | */ |
| | | abstract function folder_exists($folder, $subscription = false); |
| | | |
| | | |
| | | /** |
| | | * Get folder size (size of all messages in a folder) |
| | | * |
| | |
| | | */ |
| | | abstract function folder_size($folder); |
| | | |
| | | |
| | | /** |
| | | * Returns the namespace where the folder is in |
| | | * |
| | |
| | | * @return string One of 'personal', 'other' or 'shared' |
| | | */ |
| | | abstract function folder_namespace($folder); |
| | | |
| | | |
| | | /** |
| | | * Gets folder attributes (from LIST response, e.g. \Noselect, \Noinferiors). |
| | |
| | | */ |
| | | abstract function folder_attributes($folder, $force = false); |
| | | |
| | | |
| | | /** |
| | | * Gets connection (and current folder) data: UIDVALIDITY, EXISTS, RECENT, |
| | | * PERMANENTFLAGS, UIDNEXT, UNSEEN |
| | |
| | | */ |
| | | abstract function folder_data($folder); |
| | | |
| | | |
| | | /** |
| | | * Returns extended information about the folder. |
| | | * |
| | |
| | | */ |
| | | abstract function folder_info($folder); |
| | | |
| | | |
| | | /** |
| | | * Returns current status of a folder |
| | | * Returns current status of a folder (compared to the last time use) |
| | | * |
| | | * @param string $folder Folder name |
| | | * @param array $diff Difference data |
| | | * |
| | | * @return int Folder status |
| | | */ |
| | | abstract function folder_status($folder = null); |
| | | |
| | | abstract function folder_status($folder = null, &$diff = array()); |
| | | |
| | | /** |
| | | * Synchronizes messages cache. |
| | |
| | | * @param string $folder Folder name |
| | | */ |
| | | abstract function folder_sync($folder); |
| | | |
| | | |
| | | /** |
| | | * Modify folder name according to namespace. |
| | |
| | | */ |
| | | abstract function mod_folder($folder, $mode = 'out'); |
| | | |
| | | |
| | | /** |
| | | * Create all folders specified as default |
| | | */ |
| | | public function create_default_folders() |
| | | { |
| | | $rcube = rcube::get_instance(); |
| | | |
| | | // create default folders if they do not exist |
| | | foreach ($this->default_folders as $folder) { |
| | | if (!$this->folder_exists($folder)) { |
| | | $this->create_folder($folder, true); |
| | | } |
| | | else if (!$this->folder_exists($folder, true)) { |
| | | $this->subscribe($folder); |
| | | foreach (self::$folder_types as $type) { |
| | | if ($folder = $rcube->config->get($type . '_mbox')) { |
| | | if (!$this->folder_exists($folder)) { |
| | | $this->create_folder($folder, true, $type); |
| | | } |
| | | else if (!$this->folder_exists($folder, true)) { |
| | | $this->subscribe($folder); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Check if specified folder is a special folder |
| | | */ |
| | | public function is_special_folder($name) |
| | | { |
| | | return $name == 'INBOX' || in_array($name, $this->get_special_folders()); |
| | | } |
| | | |
| | | /** |
| | | * Return configured special folders |
| | | */ |
| | | public function get_special_folders($forced = false) |
| | | { |
| | | // getting config might be expensive, store special folders in memory |
| | | if (!isset($this->icache['special-folders'])) { |
| | | $rcube = rcube::get_instance(); |
| | | $this->icache['special-folders'] = array(); |
| | | |
| | | foreach (self::$folder_types as $type) { |
| | | if ($folder = $rcube->config->get($type . '_mbox')) { |
| | | $this->icache['special-folders'][$type] = $folder; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return $this->icache['special-folders']; |
| | | } |
| | | |
| | | /** |
| | | * Set special folder associations stored in backend |
| | | */ |
| | | public function set_special_folders($specials) |
| | | { |
| | | // should be overriden by storage class if backend supports special folders (SPECIAL-USE) |
| | | unset($this->icache['special-folders']); |
| | | } |
| | | |
| | | /** |
| | | * Get mailbox quota information. |
| | | * |
| | | * @param string $folder Folder name |
| | | * |
| | | * @return mixed Quota info or False if not supported |
| | | */ |
| | | abstract function get_quota(); |
| | | abstract function get_quota($folder = null); |
| | | |
| | | |
| | | /* ----------------------------------------- |
| | |
| | | */ |
| | | abstract function set_acl($folder, $user, $acl); |
| | | |
| | | |
| | | /** |
| | | * Removes any <identifier,rights> pair for the |
| | | * specified user from the ACL for the specified |
| | |
| | | */ |
| | | abstract function delete_acl($folder, $user); |
| | | |
| | | |
| | | /** |
| | | * Returns the access control list for a folder (GETACL). |
| | | * |
| | |
| | | * @return array User-rights array on success, NULL on error |
| | | */ |
| | | abstract function get_acl($folder); |
| | | |
| | | |
| | | /** |
| | | * Returns information about what rights can be granted to the |
| | |
| | | */ |
| | | abstract function list_rights($folder, $user); |
| | | |
| | | |
| | | /** |
| | | * Returns the set of rights that the current user has to a folder (MYRIGHTS). |
| | | * |
| | |
| | | * @return array MYRIGHTS response on success, NULL on error |
| | | */ |
| | | abstract function my_rights($folder); |
| | | |
| | | |
| | | /** |
| | | * Sets metadata/annotations (SETMETADATA/SETANNOTATION) |
| | |
| | | */ |
| | | abstract function set_metadata($folder, $entries); |
| | | |
| | | |
| | | /** |
| | | * Unsets metadata/annotations (SETMETADATA/SETANNOTATION) |
| | | * |
| | |
| | | * @return boolean True on success, False on failure |
| | | */ |
| | | abstract function delete_metadata($folder, $entries); |
| | | |
| | | |
| | | /** |
| | | * Returns folder metadata/annotations (GETMETADATA/GETANNOTATION). |
| | |
| | | * @return array Metadata entry-value hash array on success, NULL on error |
| | | */ |
| | | abstract function get_metadata($folder, $entries, $options = array()); |
| | | |
| | | |
| | | /* ----------------------------------------- |
| | | * Cache related functions |
| | |
| | | */ |
| | | abstract function clear_cache($key = null, $prefix_mode = false); |
| | | |
| | | |
| | | /** |
| | | * Returns cached value |
| | | * |
| | |
| | | */ |
| | | abstract function get_cache($key); |
| | | |
| | | |
| | | /** |
| | | * Delete outdated cache entries |
| | | */ |
| | | abstract function expunge_cache(); |
| | | |
| | | } // end class rcube_storage |
| | | abstract function cache_gc(); |
| | | } |