summaryrefslogtreecommitdiff
path: root/program/include
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2009-04-19 17:44:29 +0000
committerthomascube <thomas@roundcube.net>2009-04-19 17:44:29 +0000
commitcc97ea0559af1a92a54dbcdf738ee4d95e67d3ff (patch)
treef9e18128e5a90abb06f079b09f8cd9ed92044faf /program/include
parentfb253ee9a89e2da779d11058f1f0c63c314b2840 (diff)
Merged branch devel-api (from r2208 to r2387) back into trunk (omitting some sample plugins)
Diffstat (limited to 'program/include')
-rw-r--r--program/include/html.php30
-rwxr-xr-xprogram/include/iniset.php2
-rw-r--r--program/include/main.inc25
-rw-r--r--program/include/rcmail.php44
-rw-r--r--program/include/rcube_addressbook.php169
-rw-r--r--program/include/rcube_config.php1
-rw-r--r--program/include/rcube_contacts.php35
-rw-r--r--program/include/rcube_html_page.php11
-rw-r--r--program/include/rcube_imap.php31
-rw-r--r--program/include/rcube_json_output.php26
-rw-r--r--program/include/rcube_ldap.php2
-rw-r--r--program/include/rcube_message.php3
-rw-r--r--program/include/rcube_plugin.php196
-rw-r--r--program/include/rcube_plugin_api.php312
-rwxr-xr-xprogram/include/rcube_template.php112
-rw-r--r--program/include/rcube_user.php26
-rw-r--r--program/include/rcube_vcard.php4
17 files changed, 875 insertions, 154 deletions
diff --git a/program/include/html.php b/program/include/html.php
index 01ad41544..78e696cb6 100644
--- a/program/include/html.php
+++ b/program/include/html.php
@@ -33,7 +33,7 @@ class html
protected $content;
public static $common_attrib = array('id','class','style','title','align');
- public static $containers = array('iframe','div','span','p','h1','h2','h3','form','textarea','table','tr','th','td','style');
+ public static $containers = array('iframe','div','span','p','h1','h2','h3','form','textarea','table','tr','th','td','style','script');
public static $lc_tags = true;
/**
@@ -599,6 +599,34 @@ class html_table extends html
$this->header[] = $cell;
}
+ /**
+ * Remove a column from a table
+ * Useful for plugins making alterations
+ *
+ * @param string $class
+ */
+ public function remove_column($class)
+ {
+ // Remove the header
+ foreach($this->header as $index=>$header){
+ if($header->attrib['class'] == $class){
+ unset($this->header[$index]);
+ break;
+ }
+ }
+
+ // Remove cells from rows
+ foreach($this->rows as $i=>$row){
+ foreach($row->cells as $j=>$cell){
+ if($cell->attrib['class'] == $class){
+ unset($this->rows[$i]->cells[$j]);
+ break;
+ }
+ }
+ }
+ }
+
+
/**
* Jump to next row
*
diff --git a/program/include/iniset.php b/program/include/iniset.php
index 234f9ebcb..46f3750ea 100755
--- a/program/include/iniset.php
+++ b/program/include/iniset.php
@@ -22,7 +22,7 @@
// application constants
-define('RCMAIL_VERSION', '0.2-trunk');
+define('RCMAIL_VERSION', '0.3-trunk');
define('RCMAIL_CHARSET', 'UTF-8');
define('JS_OBJECT_NAME', 'rcmail');
diff --git a/program/include/main.inc b/program/include/main.inc
index b22be1aca..b3d0dab2a 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -88,9 +88,9 @@ function get_sequence_name($sequence)
* @return string Localized text
* @see rcmail::gettext()
*/
-function rcube_label($p)
+function rcube_label($p, $domain=null)
{
- return rcmail::get_instance()->gettext($p);
+ return rcmail::get_instance()->gettext($p, $domain);
}
@@ -302,12 +302,11 @@ function rcube_charset_convert($str, $from, $to=NULL)
*/
function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
{
- global $OUTPUT;
static $html_encode_arr = false;
static $js_rep_table = false;
static $xml_rep_table = false;
- $charset = $OUTPUT->get_charset();
+ $charset = rcmail::get_instance()->config->get('charset', RCMAIL_CHARSET);
$is_iso_8859_1 = false;
if ($charset == 'ISO-8859-1') {
$is_iso_8859_1 = true;
@@ -692,11 +691,11 @@ function parse_attrib_string($str)
preg_match_all('/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/Ui', stripslashes($str), $regs, PREG_SET_ORDER);
// convert attributes to an associative array (name => value)
- if ($regs)
- foreach ($regs as $attr)
- {
- $attrib[strtolower($attr[1])] = $attr[3] . $attr[4];
- }
+ if ($regs) {
+ foreach ($regs as $attr) {
+ $attrib[strtolower($attr[1])] = html_entity_decode($attr[3] . $attr[4]);
+ }
+ }
return $attrib;
}
@@ -829,9 +828,13 @@ function format_email_recipient($email, $name='')
*/
function console()
{
+ $args = func_get_args();
+ if (class_exists('rcmail', false))
+ rcmail::get_instance()->plugins->exec_hook('console', $args);
+
$msg = array();
- foreach (func_get_args() as $arg)
- $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
+ foreach ($args as $arg)
+ $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
if (!($GLOBALS['CONFIG']['debug_level'] & 4))
write_log('console', join(";\n", $msg));
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 9aad25b27..56fc2f5db 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -37,6 +37,7 @@ class rcmail
public $db;
public $imap;
public $output;
+ public $plugins;
public $task = 'mail';
public $action = '';
public $comm_path = './';
@@ -88,7 +89,7 @@ class rcmail
$syslog_facility = $this->config->get('syslog_facility', LOG_USER);
openlog($syslog_id, LOG_ODELAY, $syslog_facility);
}
-
+
// set task and action properties
$this->set_task(strip_quotes(get_input_value('_task', RCUBE_INPUT_GPC)));
$this->action = asciiwords(get_input_value('_action', RCUBE_INPUT_GPC));
@@ -131,6 +132,9 @@ class rcmail
// create IMAP object
if ($this->task == 'mail')
$this->imap_init();
+
+ // create plugin API and load plugins
+ $this->plugins = rcube_plugin_api::get_instance();
}
@@ -255,10 +259,19 @@ class rcmail
$contacts = null;
$ldap_config = (array)$this->config->get('ldap_public');
$abook_type = strtolower($this->config->get('address_book_type'));
+
+ $plugin = $this->plugins->exec_hook('get_address_book', array('id' => $id, 'writeable' => $writeable));
- if ($id && $ldap_config[$id]) {
+ // plugin returned instance of a rcube_addressbook
+ if ($plugin['instance'] instanceof rcube_addressbook) {
+ $contacts = $plugin['instance'];
+ }
+ else if ($id && $ldap_config[$id]) {
$contacts = new rcube_ldap($ldap_config[$id]);
}
+ else if ($id === '0') {
+ $contacts = new rcube_contacts($this->db, $this->user->ID);
+ }
else if ($abook_type == 'ldap') {
// Use the first writable LDAP address book.
foreach ($ldap_config as $id => $prop) {
@@ -598,7 +611,7 @@ class rcmail
* @param mixed Named parameters array or label name
* @return string Localized text
*/
- public function gettext($attrib)
+ public function gettext($attrib, $domain=null)
{
// load localization files if not done yet
if (empty($this->texts))
@@ -613,9 +626,12 @@ class rcmail
$command_name = !empty($attrib['command']) ? $attrib['command'] : NULL;
$alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : '');
-
+
+ // check for text with domain
+ if ($domain && ($text_item = $this->texts[$domain.'.'.$alias]))
+ ;
// text does not exist
- if (!($text_item = $this->texts[$alias])) {
+ else if (!($text_item = $this->texts[$alias])) {
/*
raise_error(array(
'code' => 500,
@@ -677,7 +693,7 @@ class rcmail
*
* @param string Language ID
*/
- public function load_language($lang = null)
+ public function load_language($lang = null, $add = array())
{
$lang = $this->language_prop(($lang ? $lang : $_SESSION['language']));
@@ -707,6 +723,10 @@ class rcmail
$_SESSION['language'] = $lang;
}
+
+ // append additional texts (from plugin)
+ if (is_array($add) && !empty($add))
+ $this->texts += $add;
}
@@ -920,18 +940,20 @@ class rcmail
{
if (!is_array($p))
$p = array('_action' => @func_get_arg(0));
+
+ $task = $p['_task'] ? $p['_task'] : $p['task'];
+ if (!$task || !in_array($task, rcmail::$main_tasks))
+ $task = $this->task;
- if (!$p['task'] || !in_array($p['task'], rcmail::$main_tasks))
- $p['task'] = $this->task;
-
- $p['_task'] = $p['task'];
+ $p['_task'] = $task;
unset($p['task']);
$url = './';
$delm = '?';
- foreach (array_reverse($p) as $par => $val)
+ foreach (array_reverse($p) as $key => $val)
{
if (!empty($val)) {
+ $par = $key[0] == '_' ? $key : '_'.$key;
$url .= $delm.urlencode($par).'='.urlencode($val);
$delm = '&';
}
diff --git a/program/include/rcube_addressbook.php b/program/include/rcube_addressbook.php
new file mode 100644
index 000000000..9e970f213
--- /dev/null
+++ b/program/include/rcube_addressbook.php
@@ -0,0 +1,169 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_addressbook.php |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2006-2009, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Interface to the local address book database |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+
+/**
+ * Abstract skeleton of an address book/repository
+ *
+ * @package Addressbook
+ */
+abstract class rcube_addressbook
+{
+ /** public properties */
+ var $primary_key;
+ var $readonly = true;
+ var $ready = false;
+ var $list_page = 1;
+ var $page_size = 10;
+
+ /**
+ * Save a search string for future listings
+ *
+ * @param mixed Search params to use in listing method, obtained by get_search_set()
+ */
+ abstract function set_search_set($filter);
+
+ /**
+ * Getter for saved search properties
+ *
+ * @return mixed Search properties used by this class
+ */
+ abstract function get_search_set();
+
+ /**
+ * Reset saved results and search parameters
+ */
+ abstract function reset();
+
+ /**
+ * List the current set of contact records
+ *
+ * @param array List of cols to show
+ * @param int Only return this number of records, use negative values for tail
+ * @return array Indexed list of contact records, each a hash array
+ */
+ abstract function list_records($cols=null, $subset=0);
+
+ /**
+ * Search records
+ *
+ * @param array List of fields to search in
+ * @param string Search value
+ * @param boolean True if results are requested, False if count only
+ * @return Indexed list of contact records and 'count' value
+ */
+ abstract function search($fields, $value, $strict=false, $select=true);
+
+ /**
+ * Count number of available contacts in database
+ *
+ * @return object rcube_result_set Result set with values for 'count' and 'first'
+ */
+ abstract function count();
+
+ /**
+ * Return the last result set
+ *
+ * @return object rcube_result_set Current result set or NULL if nothing selected yet
+ */
+ abstract function get_result();
+
+ /**
+ * Get a specific contact record
+ *
+ * @param mixed record identifier(s)
+ * @param boolean True to return record as associative array, otherwise a result set is returned
+ * @return mixed Result object with all record fields or False if not found
+ */
+ abstract function get_record($id, $assoc=false);
+
+ /**
+ * Close connection to source
+ * Called on script shutdown
+ */
+ function close() { }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Create a new contact record
+ *
+ * @param array Assoziative array with save data
+ * @param boolean True to check for duplicates first
+ * @return The created record ID on success, False on error
+ */
+ function insert($save_data, $check=false)
+ {
+ /* empty for read-only address books */
+ }
+
+ /**
+ * Update a specific contact record
+ *
+ * @param mixed Record identifier
+ * @param array Assoziative array with save data
+ * @return True on success, False on error
+ */
+ function update($id, $save_cols)
+ {
+ /* empty for read-only address books */
+ }
+
+ /**
+ * Mark one or more contact records as deleted
+ *
+ * @param array Record identifiers
+ */
+ function delete($ids)
+ {
+ /* empty for read-only address books */
+ }
+
+ /**
+ * Remove all records from the database
+ */
+ function delete_all()
+ {
+ /* empty for read-only address books */
+ }
+
+}
+ \ No newline at end of file
diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php
index 7be2b0d2c..1312a73de 100644
--- a/program/include/rcube_config.php
+++ b/program/include/rcube_config.php
@@ -74,6 +74,7 @@ class rcube_config
// fix paths
$this->prop['log_dir'] = $this->prop['log_dir'] ? unslashify($this->prop['log_dir']) : INSTALL_PATH . 'logs';
$this->prop['temp_dir'] = $this->prop['temp_dir'] ? unslashify($this->prop['temp_dir']) : INSTALL_PATH . 'temp';
+ $this->prop['plugins_dir'] = $this->prop['plugins_dir'] ? unslashify($this->prop['plugins_dir']) : INSTALL_PATH . 'plugins';
// fix default imap folders encoding
foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder)
diff --git a/program/include/rcube_contacts.php b/program/include/rcube_contacts.php
index 65d89ca2b..f440e5f8a 100644
--- a/program/include/rcube_contacts.php
+++ b/program/include/rcube_contacts.php
@@ -25,7 +25,7 @@
*
* @package Addressbook
*/
-class rcube_contacts
+class rcube_contacts extends rcube_addressbook
{
var $db = null;
var $db_name = '';
@@ -60,30 +60,6 @@ class rcube_contacts
/**
- * Set internal list page
- *
- * @param number Page number to list
- * @access public
- */
- function set_page($page)
- {
- $this->list_page = (int)$page;
- }
-
-
- /**
- * Set internal page size
- *
- * @param number Number of messages to display on one page
- * @access public
- */
- function set_pagesize($size)
- {
- $this->page_size = (int)$size;
- }
-
-
- /**
* Save a search string for future listings
*
* @param string SQL params to use in listing method
@@ -118,13 +94,6 @@ class rcube_contacts
/**
- * Close connection to source
- * Called on script shutdown
- */
- function close(){}
-
-
- /**
* List the current set of contact records
*
* @param array List of cols to show
@@ -233,7 +202,7 @@ class rcube_contacts
*
* @return Result array or NULL if nothing selected yet
*/
- function get_result($as_res=true)
+ function get_result()
{
return $this->result;
}
diff --git a/program/include/rcube_html_page.php b/program/include/rcube_html_page.php
index 78f6176bf..c83c6aeea 100644
--- a/program/include/rcube_html_page.php
+++ b/program/include/rcube_html_page.php
@@ -31,8 +31,8 @@ class rcube_html_page
protected $scripts = array();
protected $charset = 'UTF-8';
- protected $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
- protected $script_tag = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
+ protected $script_tag_file = "<script type=\"text/javascript\" src=\"%s\"></script>\n";
+ protected $script_tag = "<script type=\"text/javascript\">\n/* <![CDATA[ */\n%s\n/* ]]> */\n</script>";
protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
protected $title = '';
@@ -53,6 +53,9 @@ class rcube_html_page
public function include_script($file, $position='head')
{
static $sa_files = array();
+
+ if (!ereg('^https?://', $file) && $file[0] != '/')
+ $file = $this->scripts_path . $file;
if (in_array($file, $sa_files)) {
return;
@@ -165,7 +168,7 @@ class rcube_html_page
// definition of the code to be placed in the document header and footer
if (is_array($this->script_files['head'])) {
foreach ($this->script_files['head'] as $file) {
- $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file);
+ $__page_header .= sprintf($this->script_tag_file, $file);
}
}
@@ -180,7 +183,7 @@ class rcube_html_page
if (is_array($this->script_files['foot'])) {
foreach ($this->script_files['foot'] as $file) {
- $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file);
+ $__page_footer .= sprintf($this->script_tag_file, $file);
}
}
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index da7c5bf88..e2b6c0d9a 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -55,6 +55,7 @@ class rcube_imap
var $default_charset = 'ISO-8859-1';
var $default_folders = array('INBOX');
var $default_folders_lc = array('inbox');
+ var $fetch_add_headers = '';
var $cache = array();
var $cache_keys = array();
var $cache_changes = array();
@@ -428,8 +429,16 @@ class rcube_imap
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);
+ // Give plugins a chance to provide a list of mailboxes
+ $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',array('root'=>$root,'filter'=>$filter));
+ if (isset($data['folders'])) {
+ $a_folders = $data['folders'];
+ }
+ else{
+ // 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();
@@ -775,7 +784,7 @@ class rcube_imap
$cache_index = $this->get_message_cache_index($cache_key);
// fetch reuested headers from server
- $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, $msgs);
+ $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, $msgs, false, $this->fetch_add_headers);
$deleted_count = 0;
if (!empty($a_header_index))
@@ -829,14 +838,14 @@ class rcube_imap
if ($this->sort_field && $this->search_sort_field != $this->sort_field)
$this->search('', $this->search_string, $this->search_charset, $this->sort_field);
- if ($this->sort_order == 'DESC')
+ if ($this->sort_order == 'DESC')
$this->cache[$key] = array_reverse($this->search_set);
- else
- $this->cache[$key] = $this->search_set;
+ else
+ $this->cache[$key] = $this->search_set;
}
else
{
- $a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, join(',', $this->search_set), $this->sort_field);
+ $a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, join(',', $this->search_set), $this->sort_field, false);
if ($this->sort_order=="ASC")
asort($a_index);
@@ -923,7 +932,7 @@ class rcube_imap
// fetch complete headers and add to cache
- $headers = iil_C_FetchHeader($this->conn, $mailbox, $id);
+ $headers = iil_C_FetchHeader($this->conn, $mailbox, $id, false, $this->fetch_add_headers);
$this->add_message_cache($cache_key, $headers->id, $headers);
}
@@ -1062,7 +1071,7 @@ class rcube_imap
if ($uid && ($headers = &$this->get_cached_message($mailbox.'.msg', $uid)))
return $headers;
- $headers = iil_C_FetchHeader($this->conn, $mailbox, $id, $is_uid, $bodystr);
+ $headers = iil_C_FetchHeader($this->conn, $mailbox, $id, $is_uid, $bodystr, $this->fetch_add_headers);
// write headers cache
if ($headers)
@@ -2227,7 +2236,7 @@ class rcube_imap
if ($cache_count==$msg_count)
{
// get highest index
- $header = iil_C_FetchHeader($this->conn, $mailbox, "$msg_count");
+ $header = iil_C_FetchHeader($this->conn, $mailbox, "$msg_count", false, $this->fetch_add_headers);
$cache_uid = array_pop($cache_index);
// uids of highest message matches -> cache seems OK
@@ -2277,7 +2286,7 @@ class rcube_imap
// featch headers if unserialize failed
if (empty($this->cache[$cache_key][$uid]))
- $this->cache[$cache_key][$uid] = iil_C_FetchHeader($this->conn, preg_replace('/.msg$/', '', $key), $uid, true);
+ $this->cache[$cache_key][$uid] = iil_C_FetchHeader($this->conn, preg_replace('/.msg$/', '', $key), $uid, true, $this->fetch_add_headers);
}
}
diff --git a/program/include/rcube_json_output.php b/program/include/rcube_json_output.php
index 0bd3a2bad..a14f4ae14 100644
--- a/program/include/rcube_json_output.php
+++ b/program/include/rcube_json_output.php
@@ -196,26 +196,33 @@ class rcube_json_output
* @return void
* @deprecated
*/
- public function remote_response($add='', $flush=false)
+ public function remote_response($add='')
{
static $s_header_sent = false;
if (!$s_header_sent) {
$s_header_sent = true;
send_nocacheing_headers();
- header('Content-Type: application/x-javascript; charset=' . $this->get_charset());
+ header('Content-Type: text/plain; charset=' . $this->get_charset());
print '/** ajax response ['.date('d/M/Y h:i:s O')."] **/\n";
}
// unset default env vars
unset($this->env['task'], $this->env['action'], $this->env['comm_path']);
+ $rcmail = rcmail::get_instance();
+ $response = array('action' => $rcmail->action, 'unlock' => (bool)$_REQUEST['_unlock']);
+
+ if (!empty($this->env))
+ $response['env'] = $this->env;
+
+ if (!empty($this->texts))
+ $response['texts'] = $this->texts;
+
// send response code
- echo $this->get_js_commands() . $add;
+ $response['exec'] = $this->get_js_commands() . $add;
- // flush the output buffer
- if ($flush)
- flush();
+ echo json_serialize($response);
}
@@ -227,14 +234,7 @@ class rcube_json_output
private function get_js_commands()
{
$out = '';
-
- if (sizeof($this->env))
- $out .= 'this.set_env('.json_serialize($this->env).");\n";
- foreach($this->texts as $name => $text) {
- $out .= sprintf("this.add_label('%s', '%s');\n", $name, JQ($text));
- }
-
foreach ($this->commands as $i => $args) {
$method = array_shift($args);
foreach ($args as $i => $arg) {
diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php
index 016fe94d5..544c7f744 100644
--- a/program/include/rcube_ldap.php
+++ b/program/include/rcube_ldap.php
@@ -24,7 +24,7 @@
*
* @package Addressbook
*/
-class rcube_ldap
+class rcube_ldap extends rcube_addressbook
{
var $conn;
var $prop = array();
diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php
index ec3be4b00..5c03b2147 100644
--- a/program/include/rcube_message.php
+++ b/program/include/rcube_message.php
@@ -84,6 +84,9 @@ class rcube_message
else {
$this->body = $this->imap->get_body($uid);
}
+
+ // notify plugins and let them analyze this structured message object
+ $this->app->plugins->exec_hook('message_load', array('object' => $this));
}
diff --git a/program/include/rcube_plugin.php b/program/include/rcube_plugin.php
new file mode 100644
index 000000000..62f65a9e4
--- /dev/null
+++ b/program/include/rcube_plugin.php
@@ -0,0 +1,196 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_plugin.php |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2008-2009, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Abstract plugins interface/class |
+ | All plugins need to extend this class |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+/**
+ * Plugin interface class
+ *
+ * @package Core
+ */
+abstract class rcube_plugin
+{
+ public $ID;
+ public $api;
+ public $task;
+ protected $home;
+ protected $urlbase;
+
+ /**
+ * Default constructor.
+ */
+ public function __construct($api)
+ {
+ $this->ID = get_class($this);
+ $this->api = $api;
+ $this->home = $api->dir . DIRECTORY_SEPARATOR . $this->ID;
+ $this->urlbase = $api->url . $this->ID . '/';
+ }
+
+ /**
+ * Initialization method, needs to be implemented by the plugin itself
+ */
+ abstract function init();
+
+ /**
+ * Register a callback function for a specific (server-side) hook
+ *
+ * @param string Hook name
+ * @param mixed Callback function as string or array with object reference and method name
+ */
+ public function add_hook($hook, $callback)
+ {
+ $this->api->register_hook($hook, $callback);
+ }
+
+ /**
+ * Load localized texts from the plugins dir
+ *
+ * @param string Directory to search in
+ * @param mixed Make texts also available on the client (array with list or true for all)
+ */
+ public function add_texts($dir, $add2client = false)
+ {
+ $domain = $this->ID;
+
+ $lang = $_SESSION['language'];
+ $locdir = slashify(realpath(slashify($this->home) . $dir));
+ $texts = array();
+
+ foreach (array('en_US', $lang) as $lng) {
+ @include($locdir . $lng . '.inc');
+ $texts = (array)$labels + (array)$messages + (array)$texts;
+ }
+
+ // prepend domain to text keys and add to the application texts repository
+ if (!empty($texts)) {
+ $add = array();
+ foreach ($texts as $key => $value)
+ $add[$domain.'.'.$key] = $value;
+
+ $rcmail = rcmail::get_instance();
+ $rcmail->load_language($lang, $add);
+
+ // add labels to client
+ if ($add2client) {
+ $js_labels = is_array($add2client) ? array_map(array($this, 'label_map_callback'), $add2client) : array_keys($add);
+ $rcmail->output->add_label($js_labels);
+ }
+ }
+ }
+
+ /**
+ * Wrapper for rcmail::gettext() adding the plugin ID as domain
+ *
+ * @return string Localized text
+ * @see rcmail::gettext()
+ */
+ function gettext($p)
+ {
+ return rcmail::get_instance()->gettext($p, $this->ID);
+ }
+
+ /**
+ * Register a handler for a specific client-request action
+ *
+ * The callback will be executed upon a request like /?_task=mail&_action=plugin.myaction
+ *
+ * @param string Action name (should be unique)
+ * @param mixed Callback function as string or array with object reference and method name
+ */
+ public function register_action($action, $callback)
+ {
+ $this->api->register_action($action, $this->ID, $callback);
+ }
+
+ /**
+ * Register a handler function for a template object
+ *
+ * When parsing a template for display, tags like <roundcube:object name="plugin.myobject" />
+ * will be replaced by the return value if the registered callback function.
+ *
+ * @param string Object name (should be unique and start with 'plugin.')
+ * @param mixed Callback function as string or array with object reference and method name
+ */
+ public function register_handler($name, $callback)
+ {
+ $this->api->register_handler($name, $this->ID, $callback);
+ }
+
+ /**
+ * Make this javascipt file available on the client
+ *
+ * @param string File path; absolute or relative to the plugin directory
+ */
+ public function include_script($fn)
+ {
+ $this->api->include_script($this->ressource_url($fn));
+ }
+
+ /**
+ * Make this stylesheet available on the client
+ *
+ * @param string File path; absolute or relative to the plugin directory
+ */
+ public function include_stylesheet($fn)
+ {
+ $this->api->include_stylesheet($this->ressource_url($fn));
+ }
+
+ /**
+ * Append a button to a certain container
+ *
+ * @param array Hash array with named parameters (as used in skin templates)
+ * @param string Container name where the buttons should be added to
+ * @see rcube_remplate::button()
+ */
+ public function add_button($p, $container)
+ {
+ if ($this->api->output->type == 'html') {
+ // fix relative paths
+ foreach (array('imagepas', 'imageact', 'imagesel') as $key)
+ if ($p[$key])
+ $p[$key] = $this->api->url . $this->ressource_url($p[$key]);
+
+ $this->api->add_content($this->api->output->button($p), $container);
+ }
+ }
+
+ /**
+ * Make the given file name link into the plugin directory
+ */
+ private function ressource_url($fn)
+ {
+ if ($fn[0] != '/' && !eregi('^https?://', $fn))
+ return $this->ID . '/' . $fn;
+ else
+ return $fn;
+ }
+
+ /**
+ * Callback function for array_map
+ */
+ private function label_map_callback($key)
+ {
+ return $this->ID.'.'.$key;
+ }
+
+
+}
+
diff --git a/program/include/rcube_plugin_api.php b/program/include/rcube_plugin_api.php
new file mode 100644
index 000000000..4780f2e7e
--- /dev/null
+++ b/program/include/rcube_plugin_api.php
@@ -0,0 +1,312 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_plugin_api.php |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2008-2009, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Plugins repository |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+/**
+ * The plugin loader and global API
+ *
+ * @package Core
+ */
+class rcube_plugin_api
+{
+ static private $instance;
+
+ public $dir;
+ public $url = 'plugins/';
+ public $output;
+
+ public $handlers = array();
+ private $plugins = array();
+ private $actions = array();
+ private $actionmap = array();
+ private $objectsmap = array();
+ private $template_contents = array();
+
+ private $required_plugins = array('filesystem_attachments');
+
+ /**
+ * This implements the 'singleton' design pattern
+ *
+ * @return object rcube_plugin_api The one and only instance if this class
+ */
+ static function get_instance()
+ {
+ if (!self::$instance) {
+ self::$instance = new rcube_plugin_api();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Private constructor
+ */
+ private function __construct()
+ {
+ $rcmail = rcmail::get_instance();
+ $this->dir = realpath($rcmail->config->get('plugins_dir'));
+ }
+
+
+ /**
+ * Load and init all enabled plugins
+ *
+ * This has to be done after rcmail::load_gui() or rcmail::init_json()
+ * was called because plugins need to have access to rcmail->output
+ */
+ public function init()
+ {
+ $rcmail = rcmail::get_instance();
+ $this->output = $rcmail->output;
+
+ $plugins_dir = dir($this->dir);
+ $plugins_enabled = (array)$rcmail->config->get('plugins', array());
+
+ foreach ($plugins_enabled as $plugin_name) {
+ $fn = $plugins_dir->path . DIRECTORY_SEPARATOR . $plugin_name . DIRECTORY_SEPARATOR . $plugin_name . '.php';
+
+ if (file_exists($fn)) {
+ include($fn);
+
+ // instantiate class if exists
+ if (class_exists($plugin_name, false)) {
+ $plugin = new $plugin_name($this);
+ // check inheritance and task specification
+ if (is_subclass_of($plugin, 'rcube_plugin') && (!$plugin->task || $plugin->task == $rcmail->task)) {
+ $plugin->init();
+ $this->plugins[] = $plugin;
+ }
+ }
+ else {
+ raise_error(array('code' => 520, 'type' => 'php', 'message' => "No plugin class $plugin_name found in $fn"), true, false);
+ }
+ }
+ else {
+ raise_error(array('code' => 520, 'type' => 'php', 'message' => "Failed to load plugin file $fn"), true, false);
+ }
+ }
+
+ // check existance of all required core plugins
+ foreach ($this->required_plugins as $plugin_name) {
+ $loaded = false;
+ foreach ($this->plugins as $plugin) {
+ if ($plugin instanceof $plugin_name) {
+ $loaded = true;
+ break;
+ }
+ }
+
+ // load required core plugin if no derivate was found
+ if (!$loaded) {
+ $fn = $plugins_dir->path . DIRECTORY_SEPARATOR . $plugin_name . DIRECTORY_SEPARATOR . $plugin_name . '.php';
+ if (file_exists($fn)) {
+ include($fn);
+
+ if (class_exists($plugin_name, false)) {
+ $plugin = new $plugin_name($this);
+ // check inheritance
+ if (is_subclass_of($plugin, 'rcube_plugin')) {
+ $plugin->init();
+ $this->plugins[] = $plugin;
+ $loaded = true;
+ }
+ }
+ }
+ }
+
+ // trigger fatal error if still not loaded
+ if (!$loaded) {
+ raise_error(array('code' => 520, 'type' => 'php', 'message' => "Requried plugin $plugin_name was not loaded"), true, true);
+ }
+ }
+
+ // register an internal hook
+ $this->register_hook('template_container', array($this, 'template_container_hook'));
+
+ // maybe also register a shudown function which triggers shutdown functions of all plugin objects
+
+
+ // call imap_init right now
+ // (should actually be done in rcmail::imap_init() but plugins are not initialized then)
+ if ($rcmail->imap) {
+ $hook = $this->exec_hook('imap_init', array('fetch_headers' => $rcmail->imap->fetch_add_headers));
+ if ($hook['fetch_headers'])
+ $rcmail->imap->fetch_add_headers = $hook['fetch_headers'];
+ }
+ }
+
+
+ /**
+ * Allows a plugin object to register a callback for a certain hook
+ *
+ * @param string Hook name
+ * @param mixed String with global function name or array($obj, 'methodname')
+ */
+ public function register_hook($hook, $callback)
+ {
+ if (is_callable($callback))
+ $this->handlers[$hook][] = $callback;
+ else
+ raise_error(array('code' => 521, 'type' => 'php', 'message' => "Invalid callback function for $hook"), true, false);
+ }
+
+
+ /**
+ * Triggers a plugin hook.
+ * This is called from the application and executes all registered handlers
+ *
+ * @param string Hook name
+ * @param array Named arguments (key->value pairs)
+ * @return array The (probably) altered hook arguments
+ */
+ public function exec_hook($hook, $args = array())
+ {
+ $args += array('abort' => false);
+
+ foreach ((array)$this->handlers[$hook] as $callback) {
+ $ret = call_user_func($callback, $args);
+ if ($ret && is_array($ret))
+ $args = $ret + $args;
+
+ if ($args['abort'])
+ break;
+ }
+
+ return $args;
+ }
+
+
+ /**
+ * Let a plugin register a handler for a specific request
+ *
+ * @param string Action name (_task=mail&_action=plugin.foo)
+ * @param string Plugin name that registers this action
+ * @param mixed Callback: string with global function name or array($obj, 'methodname')
+ */
+ public function register_action($action, $owner, $callback)
+ {
+ // check action name
+ if (strpos($action, 'plugin.') !== 0)
+ $action = 'plugin.'.$action;
+
+ // can register action only if it's not taken or registered by myself
+ if (!isset($this->actionmap[$action]) || $this->actionmap[$action] == $owner) {
+ $this->actions[$action] = $callback;
+ $this->actionmap[$action] = $owner;
+ }
+ else {
+ raise_error(array('code' => 523, 'type' => 'php', 'message' => "Cannot register action $action; already taken by another plugin"), true, false);
+ }
+ }
+
+
+ /**
+ * This method handles requests like _task=mail&_action=plugin.foo
+ * It executes the callback function that was registered with the given action.
+ *
+ * @param string Action name
+ */
+ public function exec_action($action)
+ {
+ if (isset($this->actions[$action])) {
+ call_user_func($this->actions[$action]);
+ }
+ else {
+ raise_error(array('code' => 524, 'type' => 'php', 'message' => "No handler found for action $action"), true, true);
+ }
+ }
+
+
+ /**
+ * Register a handler function for template objects
+ *
+ * @param string Object name
+ * @param string Plugin name that registers this action
+ * @param mixed Callback: string with global function name or array($obj, 'methodname')
+ */
+ public function register_handler($name, $owner, $callback)
+ {
+ // check name
+ if (strpos($name, 'plugin.') !== 0)
+ $name = 'plugin.'.$name;
+
+ // can register handler only if it's not taken or registered by myself
+ if (!isset($this->objectsmap[$name]) || $this->objectsmap[$name] == $owner) {
+ $this->output->add_handler($name, $callback);
+ $this->objectsmap[$name] = $owner;
+ }
+ else {
+ raise_error(array('code' => 525, 'type' => 'php', 'message' => "Cannot register template handler $name; already taken by another plugin"), true, false);
+ }
+ }
+
+ /**
+ * Include a plugin script file in the current HTML page
+ */
+ public function include_script($fn)
+ {
+ if ($this->output->type == 'html') {
+ $src = $this->ressource_url($fn);
+ $this->output->add_header(html::tag('script', array('type' => "text/javascript", 'src' => $src)));
+ }
+ }
+
+ /**
+ * Include a plugin stylesheet in the current HTML page
+ */
+ public function include_stylesheet($fn)
+ {
+ if ($this->output->type == 'html') {
+ $src = $this->ressource_url($fn);
+ $this->output->add_header(html::tag('link', array('rel' => "stylesheet", 'type' => "text/css", 'href' => $src)));
+ }
+ }
+
+ /**
+ * Save the given HTML content to be added to a template container
+ */
+ public function add_content($html, $container)
+ {
+ $this->template_contents[$container] .= $html . "\n";
+ }
+
+ /**
+ * Callback for template_container hooks
+ */
+ private function template_container_hook($attrib)
+ {
+ $container = $attrib['name'];
+ return array('content' => $this->template_contents[$container]);
+ }
+
+ /**
+ * Make the given file name link into the plugins directory
+ */
+ private function ressource_url($fn)
+ {
+ if ($fn[0] != '/' && !eregi('^https?://', $fn))
+ return $this->url . $fn;
+ else
+ return $fn;
+ }
+
+}
+
diff --git a/program/include/rcube_template.php b/program/include/rcube_template.php
index 1e732ca11..557509a14 100755
--- a/program/include/rcube_template.php
+++ b/program/include/rcube_template.php
@@ -66,11 +66,12 @@ class rcube_template extends rcube_html_page
$javascript = 'var '.JS_OBJECT_NAME.' = new rcube_webmail();';
// don't wait for page onload. Call init at the bottom of the page (delayed)
- $javascript_foot = "if (window.call_init)\n call_init('".JS_OBJECT_NAME."');";
+ $javascript_foot = '$(document).ready(function(){ '.JS_OBJECT_NAME.'.init(); });';
$this->add_script($javascript, 'head_top');
$this->add_script($javascript_foot, 'foot');
$this->scripts_path = 'program/js/';
+ $this->include_script('http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js');
$this->include_script('common.js');
$this->include_script('app.js');
@@ -208,8 +209,11 @@ class rcube_template extends rcube_html_page
*/
public function add_label()
{
- $arg_list = func_get_args();
- foreach ($arg_list as $i => $name) {
+ $args = func_get_args();
+ if (count($args) == 1 && is_array($args[0]))
+ $args = $args[0];
+
+ foreach ($args as $name) {
$this->command('add_label', $name, rcube_label($name));
}
}
@@ -375,9 +379,9 @@ class rcube_template extends rcube_html_page
$parent = $this->framed || preg_match('/^parent\./', $method);
$out .= sprintf(
"%s.%s(%s);\n",
- ($parent ? 'parent.' : '') . JS_OBJECT_NAME,
- preg_replace('/^parent\./', '', $method),
- implode(',', $args)
+ ($parent ? 'if(window.parent && parent.'.JS_OBJECT_NAME.') parent.' : '') . JS_OBJECT_NAME,
+ preg_replace('/^parent\./', '', $method),
+ implode(',', $args)
);
}
@@ -511,37 +515,21 @@ class rcube_template extends rcube_html_page
*/
private function parse_xml($input)
{
- return preg_replace_callback('/<roundcube:([-_a-z]+)\s+([^>]+)>/Ui', array($this, 'xml_command_callback'), $input);
- }
-
-
- /**
- * This is a callback function for preg_replace_callback (see #1485286)
- * It's only purpose is to reconfigure parameters for xml_command, so that the signature isn't disturbed
- */
- private function xml_command_callback($matches)
- {
- $str_attrib = isset($matches[2]) ? $matches[2] : '';
- $add_attrib = isset($matches[3]) ? $matches[3] : array();
-
- $command = $matches[1];
- //matches[0] is the entire matched portion of the string
-
- return $this->xml_command($command, $str_attrib, $add_attrib);
+ return preg_replace_callback('/<roundcube:([-_a-z]+)\s+([^>]+)>/Ui', array($this, 'xml_command'), $input);
}
/**
- * Convert a xml command tag into real content
+ * Callback function for parsing an xml command tag
+ * and turn it into real html content
*
- * @param string Tag command: object,button,label, etc.
- * @param string Attribute string
+ * @param array Matches array of preg_replace_callback
* @return string Tag/Object content
*/
- private function xml_command($command, $str_attrib, $add_attrib = array())
+ private function xml_command($matches)
{
- $command = strtolower($command);
- $attrib = parse_attrib_string($str_attrib) + $add_attrib;
+ $command = strtolower($matches[1]);
+ $attrib = parse_attrib_string($matches[2]);
// empty output if required condition is not met
if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) {
@@ -572,67 +560,70 @@ class rcube_template extends rcube_html_page
$incl = $this->include_php($path);
}
else {
- $incl = file_get_contents($path);
- }
+ $incl = file_get_contents($path);
+ }
return $this->parse_xml($incl);
}
break;
case 'plugin.include':
- //rcube::tfk_debug(var_export($this->config['skin_path'], true));
- $path = realpath($this->config['skin_path'].$attrib['file']);
- if (!$path) {
- //rcube::tfk_debug("Does not exist:");
- //rcube::tfk_debug($this->config['skin_path']);
- //rcube::tfk_debug($attrib['file']);
- //rcube::tfk_debug($path);
- }
- $incl = file_get_contents($path);
- if ($incl) {
- return $this->parse_xml($incl);
+ $hook = $this->app->plugins->exec_hook("template_plugin_include", $attrib);
+ return $hook['content'];
+ break;
+
+ // define a container block
+ case 'container':
+ if ($attrib['name'] && $attrib['id']) {
+ $this->command('gui_container', $attrib['name'], $attrib['id']);
+ // let plugins insert some content here
+ $hook = $this->app->plugins->exec_hook("template_container", $attrib);
+ return $hook['content'];
}
break;
// return code for a specific application object
case 'object':
$object = strtolower($attrib['name']);
+ $content = '';
// we are calling a class/method
if (($handler = $this->object_handlers[$object]) && is_array($handler)) {
if ((is_object($handler[0]) && method_exists($handler[0], $handler[1])) ||
(is_string($handler[0]) && class_exists($handler[0])))
- return call_user_func($handler, $attrib);
+ $content = call_user_func($handler, $attrib);
}
+ // execute object handler function
else if (function_exists($handler)) {
- // execute object handler function
- return call_user_func($handler, $attrib);
+ $content = call_user_func($handler, $attrib);
}
-
- if ($object=='productname') {
+ else if ($object == 'productname') {
$name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail';
- return Q($name);
+ $content = Q($name);
}
- if ($object=='version') {
+ else if ($object == 'version') {
$ver = (string)RCMAIL_VERSION;
if (is_file(INSTALL_PATH . '.svn/entries')) {
if (preg_match('/Revision:\s(\d+)/', @shell_exec('svn info'), $regs))
$ver .= ' [SVN r'.$regs[1].']';
}
- return $ver;
+ $content = Q($ver);
}
- if ($object=='steptitle') {
- return Q($this->get_pagetitle());
+ else if ($object == 'steptitle') {
+ $content = Q($this->get_pagetitle());
}
- if ($object=='pagetitle') {
+ else if ($object == 'pagetitle') {
$title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '';
$title .= $this->get_pagetitle();
- return Q($title);
+ $content = Q($title);
}
- break;
+
+ // exec plugin hooks for this template object
+ $hook = $this->app->plugins->exec_hook("template_object_$object", $attrib + array('content' => $content));
+ return $hook['content'];
// return code for a specified eval expression
case 'exp':
- $value = $this->parse_expression($attrib['expression']);
+ $value = $this->parse_expression($attrib['expression']);
return eval("return Q($value);");
// return variable
@@ -702,7 +693,7 @@ class rcube_template extends rcube_html_page
static $s_button_count = 100;
// these commands can be called directly via url
- $a_static_commands = array('compose', 'list');
+ $a_static_commands = array('compose', 'list', 'preferences', 'folders', 'identities');
if (!($attrib['command'] || $attrib['name'])) {
return '';
@@ -941,11 +932,17 @@ class rcube_template extends rcube_html_page
$default_host = $this->config['default_host'];
$_SESSION['temp'] = true;
+
+ // save original url
+ $url = get_input_value('_url', RCUBE_INPUT_POST);
+ if (empty($url) && !preg_match('/_action=logout/', $_SERVER['QUERY_STRING']))
+ $url = $_SERVER['QUERY_STRING'];
$input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30) + $attrib);
$input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30) + $attrib);
$input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login'));
$input_tzone = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_'));
+ $input_url = new html_hiddenfield(array('name' => '_url', 'id' => 'rcmloginurl', 'value' => $url));
$input_host = null;
if (is_array($default_host)) {
@@ -985,6 +982,7 @@ class rcube_template extends rcube_html_page
$out = $input_action->show();
$out .= $input_tzone->show();
+ $out .= $input_url->show();
$out .= $table->show();
// surround html output with a form tag
diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php
index 17debeb7a..b68c56cfa 100644
--- a/program/include/rcube_user.php
+++ b/program/include/rcube_user.php
@@ -346,16 +346,22 @@ class rcube_user
*/
static function create($user, $host)
{
+ $user_name = '';
$user_email = '';
$rcmail = rcmail::get_instance();
+
+ $data = $rcmail->plugins->exec_hook('create_user', array('user'=>$user, 'user_name'=>$user_name, 'user_email'=>$user_email));
+ $user_name = $data['user_name'];
+ $user_email = $data['user_email'];
+
$dbh = $rcmail->get_dbh();
// try to resolve user in virtuser table and file
- if (!strpos($user, '@')) {
+ if ($user_email != '' && !strpos($user, '@')) {
if ($email_list = self::user2email($user, false))
$user_email = $email_list[0];
}
-
+
$dbh->query(
"INSERT INTO ".get_table_name('users')."
(created, last_login, username, mail_host, alias, language)
@@ -372,7 +378,9 @@ class rcube_user
if ($user_email=='')
$user_email = strpos($user, '@') ? $user : sprintf('%s@%s', $user, $mail_domain);
- $user_name = $user != $user_email ? $user : '';
+ if ($user_name == '') {
+ $user_name = $user != $user_email ? $user : '';
+ }
if (empty($email_list))
$email_list[] = strip_newlines($user_email);
@@ -385,10 +393,10 @@ class rcube_user
(user_id, del, standard, name, email)
VALUES (?, 0, ?, ?, ?)",
$user_id,
- $standard,
+ $standard,
strip_newlines($user_name),
preg_replace('/^@/', $user . '@', $email));
- $standard = 0;
+ $standard = 0;
}
}
else
@@ -446,9 +454,9 @@ class rcube_user
while ($sql_arr = $dbh->fetch_array($sql_result))
if (strpos($sql_arr[0], '@')) {
$result[] = $sql_arr[0];
- if ($first)
- return $result[0];
- }
+ if ($first)
+ return $result[0];
+ }
}
// File lookup
$r = self::findinvirtual('[[:space:]]' . quotemeta($user) . '[[:space:]]*$');
@@ -460,7 +468,7 @@ class rcube_user
{
$result[] = trim(str_replace('\\@', '@', $arr[0]));
- if ($first)
+ if ($first)
return $result[0];
}
}
diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php
index ce5087a0f..444900cde 100644
--- a/program/include/rcube_vcard.php
+++ b/program/include/rcube_vcard.php
@@ -263,9 +263,9 @@ class rcube_vcard
$line[1] .= ';' . (strpos($prop, '=') ? $prop : 'TYPE='.$prop);
}
- if (!preg_match('/^(BEGIN|END)$/', $line[1]) && preg_match_all('/([^\\;]+);?/', $line[1], $regs2)) {
+ if (!preg_match('/^(BEGIN|END)$/i', $line[1]) && preg_match_all('/([^\\;]+);?/', $line[1], $regs2)) {
$entry = array('');
- $field = $regs2[1][0];
+ $field = strtoupper($regs2[1][0]);
foreach($regs2[1] as $attrid => $attr) {
if ((list($key, $value) = explode('=', $attr)) && $value) {