- Apply fixes from trunk up to r5401
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Make email recipients separator configurable |
| | | - Fix so folders with \Noinferiors attribute aren't listed in parent selector |
| | | - Fix handling of curly brackets in URLs (#1488168) |
| | | - Fix handling of dates (birthday/anniversary) in contact data (#1488147) |
| | | - Fix error on opening searched LDAP contact (#1488144) |
| | | - Fix redundant line break in flowed format (#1488146) |
| | | - Fix IDN address validation issue (#1488137) |
| | | - Fix JS error when dst_active checkbox doesn't exist (#1488133) |
| | | - Autocomplete LDAP records when adding contacts from mail (#1488073) |
| | |
| | | | Main configuration file | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2010, The Roundcube Dev Team | |
| | | | Copyright (C) 2005-2011, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | |
| | | // Makes that words with symbols will be ignored (e.g. g@@gle) |
| | | $rcmail_config['spellcheck_ignore_syms'] = false; |
| | | |
| | | // Use this char/string to separate recipients when composing a new message |
| | | $rcmail_config['recipients_separator'] = ','; |
| | | |
| | | // don't let users set pagesize to more than this value if set |
| | | $rcmail_config['max_pagesize'] = 200; |
| | | |
| | |
| | | * Convert the given date to a human readable form |
| | | * This uses the date formatting properties from config |
| | | * |
| | | * @param mixed Date representation (string or timestamp) |
| | | * @param mixed Date representation (string or timestamp) |
| | | * @param string Date format to use |
| | | * @param bool Enables date convertion according to user timezone |
| | | * |
| | | * @return string Formatted date string |
| | | */ |
| | | function format_date($date, $format=NULL) |
| | | function format_date($date, $format=NULL, $convert=true) |
| | | { |
| | | global $RCMAIL, $CONFIG; |
| | | |
| | | $ts = NULL; |
| | | |
| | | if (!empty($date)) |
| | | $ts = rcube_strtotime($date); |
| | |
| | | if (empty($ts)) |
| | | return ''; |
| | | |
| | | // get user's timezone offset |
| | | $tz = $RCMAIL->config->get_timezone(); |
| | | if ($convert) { |
| | | // get user's timezone offset |
| | | $tz = $RCMAIL->config->get_timezone(); |
| | | |
| | | // convert time to user's timezone |
| | | $timestamp = $ts - date('Z', $ts) + ($tz * 3600); |
| | | // convert time to user's timezone |
| | | $timestamp = $ts - date('Z', $ts) + ($tz * 3600); |
| | | |
| | | // get current timestamp in user's timezone |
| | | $now = time(); // local time |
| | | $now -= (int)date('Z'); // make GMT time |
| | | $now += ($tz * 3600); // user's time |
| | | $now_date = getdate($now); |
| | | |
| | | $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']); |
| | | $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']); |
| | | // get current timestamp in user's timezone |
| | | $now = time(); // local time |
| | | $now -= (int)date('Z'); // make GMT time |
| | | $now += ($tz * 3600); // user's time |
| | | } |
| | | else { |
| | | $now = time(); |
| | | $timestamp = $ts; |
| | | } |
| | | |
| | | // define date format depending on current time |
| | | if (!$format) { |
| | | $now_date = getdate($now); |
| | | $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']); |
| | | $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']); |
| | | |
| | | if ($CONFIG['prettydate'] && $timestamp > $today_limit && $timestamp < $now) { |
| | | $format = $RCMAIL->config->get('date_today', $RCMAIL->config->get('time_format', 'H:i')); |
| | | $today = true; |
| | |
| | | if ($p['noselection']) |
| | | $select->add($p['noselection'], ''); |
| | | |
| | | rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p['exceptions']); |
| | | rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p); |
| | | |
| | | return $select; |
| | | } |
| | |
| | | $path .= $prefix.$currentFolder; |
| | | |
| | | if (!isset($arrFolders[$currentFolder])) { |
| | | // Check \Noselect option (if options are in cache) |
| | | if (!$virtual && ($opts = $RCMAIL->imap->mailbox_options($path))) { |
| | | $virtual = in_array('\\Noselect', $opts); |
| | | // Check \Noselect attribute (if attributes are in cache) |
| | | if (!$virtual && ($attrs = $RCMAIL->imap->mailbox_attributes($path))) { |
| | | $virtual = in_array('\\Noselect', $attrs); |
| | | } |
| | | |
| | | $arrFolders[$currentFolder] = array( |
| | |
| | | * @access private |
| | | * @return string |
| | | */ |
| | | function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $exceptions=array()) |
| | | function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $opts=array()) |
| | | { |
| | | global $RCMAIL; |
| | | |
| | | $out = ''; |
| | | |
| | | foreach ($arrFolders as $key => $folder) { |
| | | if (empty($exceptions) || !in_array($folder['id'], $exceptions)) { |
| | | if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) |
| | | $foldername = rcube_label($folder_class); |
| | | else { |
| | | $foldername = $folder['name']; |
| | | |
| | | // shorten the folder name to a given length |
| | | if ($maxlength && $maxlength>1) |
| | | $foldername = abbreviate_string($foldername, $maxlength); |
| | | } |
| | | |
| | | $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); |
| | | } |
| | | else if ($nestLevel) |
| | | // skip exceptions (and its subfolders) |
| | | if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { |
| | | continue; |
| | | } |
| | | |
| | | // skip folders in which it isn't possible to create subfolders |
| | | if (!empty($opts['skip_noinferiors']) && ($attrs = $RCMAIL->imap->mailbox_attributes($folder['id'])) |
| | | && in_array('\\Noinferiors', $attrs) |
| | | ) { |
| | | continue; |
| | | } |
| | | |
| | | if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) |
| | | $foldername = rcube_label($folder_class); |
| | | else { |
| | | $foldername = $folder['name']; |
| | | |
| | | // shorten the folder name to a given length |
| | | if ($maxlength && $maxlength>1) |
| | | $foldername = abbreviate_string($foldername, $maxlength); |
| | | } |
| | | |
| | | $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); |
| | | |
| | | if (!empty($folder['folders'])) |
| | | $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, |
| | | $select, $realnames, $nestLevel+1, $exceptions); |
| | | $select, $realnames, $nestLevel+1, $opts); |
| | | } |
| | | |
| | | return $out; |
| | |
| | | return; |
| | | |
| | | $this->imap = new rcube_imap(); |
| | | $this->imap->debug_level = $this->config->get('debug_level'); |
| | | $this->imap->skip_deleted = $this->config->get('skip_deleted'); |
| | | |
| | | // enable caching of imap data |
| | |
| | | private $user_id = 0; |
| | | private $filter = null; |
| | | private $result = null; |
| | | private $name; |
| | | private $cache; |
| | | private $table_cols = array('name', 'email', 'firstname', 'surname'); |
| | | private $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'nickname', |
| | |
| | | |
| | | // public properties |
| | | public $primary_key = 'contact_id'; |
| | | public $name; |
| | | public $readonly = false; |
| | | public $groups = true; |
| | | public $undelete = true; |
| | |
| | | */ |
| | | class rcube_imap |
| | | { |
| | | public $debug_level = 1; |
| | | public $skip_deleted = false; |
| | | public $page_size = 10; |
| | | public $list_page = 1; |
| | |
| | | function set_options($opt) |
| | | { |
| | | $this->options = array_merge($this->options, (array)$opt); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Activate/deactivate debug mode |
| | | * |
| | | * @param boolean $dbg True if IMAP conversation should be logged |
| | | * @access public |
| | | */ |
| | | function set_debug($dbg = true) |
| | | { |
| | | $this->options['debug'] = $dbg; |
| | | $this->conn->setDebug($dbg, array($this, 'debug_handler')); |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | function list_unsubscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) |
| | | { |
| | | // @TODO: caching |
| | | $cache_key = $root.':'.$name; |
| | | if (!empty($filter)) { |
| | | $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter)); |
| | | } |
| | | $cache_key .= ':'.$rights; |
| | | $cache_key = 'mailboxes.list.'.md5($cache_key); |
| | | |
| | | // get cached folder list |
| | | $a_mboxes = $this->get_cache($cache_key); |
| | | if (is_array($a_mboxes)) { |
| | | return $a_mboxes; |
| | | } |
| | | |
| | | // Give plugins a chance to provide a list of mailboxes |
| | | $data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list', |
| | | array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LIST')); |
| | |
| | | array_unshift($a_mboxes, 'INBOX'); |
| | | } |
| | | |
| | | // cache folder attributes |
| | | if ($root == '' && $name == '*' && empty($filter)) { |
| | | $this->update_cache('mailboxes.attributes', $this->conn->data['LIST']); |
| | | } |
| | | |
| | | // filter folders list according to rights requirements |
| | | if ($rights && $this->get_capability('ACL')) { |
| | | $a_folders = $this->filter_rights($a_folders, $rights); |
| | |
| | | if (!$skip_sort) { |
| | | $a_mboxes = $this->_sort_mailbox_list($a_mboxes); |
| | | } |
| | | |
| | | // write mailboxlist to cache |
| | | $this->update_cache($cache_key, $a_mboxes); |
| | | |
| | | return $a_mboxes; |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * Gets folder options from LIST response, e.g. \Noselect, \Noinferiors |
| | | * Gets folder attributes from LIST response, e.g. \Noselect, \Noinferiors |
| | | * |
| | | * @param string $mailbox Folder name |
| | | * @param bool $force Set to True if options should be refreshed |
| | | * Options are available after LIST command only |
| | | * @param bool $force Set to True if attributes should be refreshed |
| | | * |
| | | * @return array Options list |
| | | */ |
| | | function mailbox_options($mailbox, $force=false) |
| | | function mailbox_attributes($mailbox, $force=false) |
| | | { |
| | | if ($mailbox == 'INBOX') { |
| | | return array(); |
| | | // get attributes directly from LIST command |
| | | if (!empty($this->conn->data['LIST']) && is_array($this->conn->data['LIST'][$mailbox])) { |
| | | $opts = $this->conn->data['LIST'][$mailbox]; |
| | | } |
| | | // get cached folder attributes |
| | | else if (!$force) { |
| | | $opts = $this->get_cache('mailboxes.attributes'); |
| | | $opts = $opts[$mailbox]; |
| | | } |
| | | |
| | | if (!is_array($this->conn->data['LIST']) || !is_array($this->conn->data['LIST'][$mailbox])) { |
| | | if ($force) { |
| | | $this->conn->listMailboxes('', $mailbox); |
| | | } |
| | | else { |
| | | return array(); |
| | | } |
| | | if (!is_array($opts)) { |
| | | $this->conn->listMailboxes('', $mailbox); |
| | | $opts = $this->conn->data['LIST'][$mailbox]; |
| | | } |
| | | |
| | | $opts = $this->conn->data['LIST'][$mailbox]; |
| | | |
| | | return is_array($opts) ? $opts : array(); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | $options['name'] = $mailbox; |
| | | $options['options'] = $this->mailbox_options($mailbox, true); |
| | | $options['namespace'] = $this->mailbox_namespace($mailbox); |
| | | $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array(); |
| | | $options['special'] = in_array($mailbox, $this->default_folders); |
| | | $options['name'] = $mailbox; |
| | | $options['attributes'] = $this->mailbox_attributes($mailbox, true); |
| | | $options['namespace'] = $this->mailbox_namespace($mailbox); |
| | | $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array(); |
| | | $options['special'] = in_array($mailbox, $this->default_folders); |
| | | |
| | | // Set 'noselect' and 'norename' flags |
| | | if (is_array($options['options'])) { |
| | | foreach ($options['options'] as $opt) { |
| | | $opt = strtolower($opt); |
| | | if ($opt == '\noselect' || $opt == '\nonexistent') { |
| | | if (is_array($options['attributes'])) { |
| | | foreach ($options['attributes'] as $attrib) { |
| | | $attrib = strtolower($attrib); |
| | | if ($attrib == '\noselect' || $attrib == '\nonexistent') { |
| | | $options['noselect'] = true; |
| | | } |
| | | } |
| | |
| | | list($code, $response) = $this->execute($subscribed ? 'LSUB' : 'LIST', $args); |
| | | |
| | | if ($code == self::ERROR_OK) { |
| | | $folders = array(); |
| | | while ($this->tokenizeResponse($response, 1) == '*') { |
| | | $cmd = strtoupper($this->tokenizeResponse($response, 1)); |
| | | $folders = array(); |
| | | $last = 0; |
| | | $pos = 0; |
| | | $response .= "\r\n"; |
| | | |
| | | while ($pos = strpos($response, "\r\n", $pos+1)) { |
| | | // literal string, not real end-of-command-line |
| | | if ($response[$pos-1] == '}') { |
| | | continue; |
| | | } |
| | | |
| | | $line = substr($response, $last, $pos - $last); |
| | | $last = $pos + 2; |
| | | |
| | | if (!preg_match('/^\* (LIST|LSUB|STATUS) /i', $line, $m)) { |
| | | continue; |
| | | } |
| | | $cmd = strtoupper($m[1]); |
| | | $line = substr($line, strlen($m[0])); |
| | | |
| | | // * LIST (<options>) <delimiter> <mailbox> |
| | | if ($cmd == 'LIST' || $cmd == 'LSUB') { |
| | | list($opts, $delim, $mailbox) = $this->tokenizeResponse($response, 3); |
| | | list($opts, $delim, $mailbox) = $this->tokenizeResponse($line, 3); |
| | | |
| | | // Add to result array |
| | | if (!$lstatus) { |
| | |
| | | } |
| | | |
| | | // Add to options array |
| | | if (!empty($opts)) { |
| | | if (empty($this->data['LIST'][$mailbox])) |
| | | $this->data['LIST'][$mailbox] = $opts; |
| | | else |
| | | $this->data['LIST'][$mailbox] = array_unique(array_merge( |
| | | $this->data['LIST'][$mailbox], $opts)); |
| | | } |
| | | if (empty($this->data['LIST'][$mailbox])) |
| | | $this->data['LIST'][$mailbox] = $opts; |
| | | else if (!empty($opts)) |
| | | $this->data['LIST'][$mailbox] = array_unique(array_merge( |
| | | $this->data['LIST'][$mailbox], $opts)); |
| | | } |
| | | // * STATUS <mailbox> (<result>) |
| | | else if ($cmd == 'STATUS') { |
| | | list($mailbox, $status) = $this->tokenizeResponse($response, 2); |
| | | list($mailbox, $status) = $this->tokenizeResponse($line, 2); |
| | | |
| | | for ($i=0, $len=count($status); $i<$len; $i += 2) { |
| | | list($name, $value) = $this->tokenizeResponse($status, 2); |
| | | $folders[$mailbox][$name] = $value; |
| | | } |
| | | } |
| | | // other untagged response line, skip it |
| | | else { |
| | | $response = ltrim($response); |
| | | if (($position = strpos($response, "\n")) !== false) |
| | | $response = substr($response, $position+1); |
| | | else |
| | | $response = ''; |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | // String atom, number, NIL, *, % |
| | | default: |
| | | // empty or one character |
| | | if ($str === '') { |
| | | // empty string |
| | | if ($str === '' || $str === null) { |
| | | break 2; |
| | | } |
| | | if (strlen($str) < 2) { |
| | | $result[] = $str; |
| | | $str = ''; |
| | | break; |
| | | } |
| | | |
| | | // excluded chars: SP, CTL, ), [, ] |
| | |
| | | |
| | | |
| | | /** |
| | | * Activate/deactivate debug mode |
| | | * |
| | | * @param boolean $dbg True if LDAP commands should be logged |
| | | * @access public |
| | | */ |
| | | function set_debug($dbg = true) |
| | | { |
| | | $this->debug = $dbg; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Quotes attribute value string |
| | | * |
| | | * @param string $str Attribute value |
| | |
| | | */ |
| | | class rcube_mdb2 |
| | | { |
| | | var $db_dsnw; // DSN for write operations |
| | | var $db_dsnr; // DSN for read operations |
| | | var $db_connected = false; // Already connected ? |
| | | var $db_mode = ''; // Connection mode |
| | | var $db_handle = 0; // Connection handle |
| | | var $db_error = false; |
| | | var $db_error_msg = ''; |
| | | public $db_dsnw; // DSN for write operations |
| | | public $db_dsnr; // DSN for read operations |
| | | public $db_connected = false; // Already connected ? |
| | | public $db_mode = ''; // Connection mode |
| | | public $db_handle = 0; // Connection handle |
| | | public $db_error = false; |
| | | public $db_error_msg = ''; |
| | | |
| | | private $debug_mode = false; |
| | | private $write_failure = false; |
| | | private $conn_failure = false; |
| | | private $a_query_results = array('dummy'); |
| | | private $last_res_id = 0; |
| | | private $tables; |
| | |
| | | */ |
| | | function __construct($db_dsnw, $db_dsnr='', $pconn=false) |
| | | { |
| | | if ($db_dsnr == '') |
| | | if (empty($db_dsnr)) |
| | | $db_dsnr = $db_dsnw; |
| | | |
| | | $this->db_dsnw = $db_dsnw; |
| | |
| | | */ |
| | | function db_connect($mode) |
| | | { |
| | | // previous connection failed, don't attempt to connect again |
| | | if ($this->conn_failure) { |
| | | return; |
| | | } |
| | | |
| | | // no replication |
| | | if ($this->db_dsnw == $this->db_dsnr) { |
| | | $mode = 'w'; |
| | | } |
| | | |
| | | // Already connected |
| | | if ($this->db_connected) { |
| | | // connected to read-write db, current connection is ok |
| | | if ($this->db_mode == 'w' && !$this->write_failure) |
| | | return; |
| | | |
| | | // no replication, current connection is ok for read and write |
| | | if (empty($this->db_dsnr) || $this->db_dsnw == $this->db_dsnr) { |
| | | $this->db_mode = 'w'; |
| | | // connected to db with the same or "higher" mode |
| | | if ($this->db_mode == 'w' || $this->db_mode == $mode) { |
| | | return; |
| | | } |
| | | |
| | | // Same mode, current connection is ok |
| | | if ($this->db_mode == $mode) |
| | | return; |
| | | } |
| | | |
| | | $dsn = ($mode == 'r') ? $this->db_dsnr : $this->db_dsnw; |
| | | |
| | | $this->db_handle = $this->dsn_connect($dsn); |
| | | $this->db_handle = $this->dsn_connect($dsn); |
| | | $this->db_connected = !PEAR::isError($this->db_handle); |
| | | |
| | | if ($this->db_connected) |
| | | $this->db_mode = $mode; |
| | | $this->db_mode = $mode; |
| | | else |
| | | $this->conn_failure = true; |
| | | } |
| | | |
| | | |
| | |
| | | // Read or write ? |
| | | $mode = (strtolower(substr(trim($query),0,6)) == 'select') ? 'r' : 'w'; |
| | | |
| | | // don't event attempt to connect if previous write-operation failed |
| | | if ($this->write_failure && $mode == 'w') |
| | | return false; |
| | | |
| | | $this->db_connect($mode); |
| | | |
| | | // check connection before proceeding |
| | |
| | | raise_error(array('code' => 500, 'type' => 'db', |
| | | 'line' => __LINE__, 'file' => __FILE__, |
| | | 'message' => $this->db_error_msg), true, false); |
| | | |
| | | |
| | | $result = false; |
| | | } |
| | | else { |
| | |
| | | $q->free(); |
| | | } |
| | | } |
| | | |
| | | // remember that write-operation failed |
| | | if ($mode == 'w' && ($result === false || PEAR::isError($result))) |
| | | $this->write_failure = true; |
| | | |
| | | // add result, even if it's an error |
| | | return $this->_add_result($result); |
| | |
| | | if (!PEAR::isError($result = $this->db_handle->listTableFields($table))) { |
| | | return $result; |
| | | } |
| | | |
| | | |
| | | return null; |
| | | } |
| | | |
| | |
| | | */ |
| | | function now() |
| | | { |
| | | switch($this->db_provider) { |
| | | switch ($this->db_provider) { |
| | | case 'mssql': |
| | | case 'sqlsrv': |
| | | return "getdate()"; |
| | |
| | | // Support unicode/punycode in top-level domain part |
| | | $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})'; |
| | | $url1 = '.:;,'; |
| | | $url2 = 'a-z0-9%=#@+?&\\/_~\\[\\]-'; |
| | | $url2 = 'a-z0-9%=#@+?&\\/_~\\[\\]{}-'; |
| | | |
| | | $this->link_pattern = "/([\w]+:\/\/|\Wwww\.)($utf_domain([$url1]?[$url2]+)*)/i"; |
| | | $this->mailto_pattern = "/(" |
| | |
| | | |
| | | function rcube_webmail() |
| | | { |
| | | this.env = {}; |
| | | this.env = { recipients_separator:',', recipients_delimiter:', ' }; |
| | | this.labels = {}; |
| | | this.buttons = {}; |
| | | this.buttons_sel = {}; |
| | |
| | | |
| | | this.init_address_input_events = function(obj, props) |
| | | { |
| | | this.env.recipients_delimiter = this.env.recipients_separator + ' '; |
| | | |
| | | obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); }) |
| | | .attr('autocomplete', 'off'); |
| | | }; |
| | |
| | | |
| | | // insert all members of a group |
| | | if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].id) { |
| | | insert += this.env.contacts[id].name + ', '; |
| | | insert += this.env.contacts[id].name + this.env.recipients_delimiter; |
| | | this.group2expand = $.extend({}, this.env.contacts[id]); |
| | | this.group2expand.input = this.ksearch_input; |
| | | this.http_request('mail/group-expand', '_source='+urlencode(this.env.contacts[id].source)+'&_gid='+urlencode(this.env.contacts[id].id), false); |
| | | } |
| | | else if (typeof this.env.contacts[id] === 'string') { |
| | | insert = this.env.contacts[id] + ', '; |
| | | insert = this.env.contacts[id] + this.env.recipients_delimiter; |
| | | trigger = true; |
| | | } |
| | | |
| | |
| | | |
| | | // get string from current cursor pos to last comma |
| | | var cpos = this.get_caret_pos(this.ksearch_input), |
| | | p = inp_value.lastIndexOf(',', cpos-1), |
| | | p = inp_value.lastIndexOf(this.env.recipients_separator, cpos-1), |
| | | q = inp_value.substring(p+1, cpos), |
| | | min = this.env.autocomplete_min_length, |
| | | ac = this.ksearch_data; |
| | |
| | | $RCMAIL->output->set_env('month_names', $month_names); |
| | | } |
| | | $colprop['class'] .= ($colprop['class'] ? ' ' : '') . 'datepicker'; |
| | | $val = format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d')); |
| | | $val = format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d'), false); |
| | | } |
| | | |
| | | $val = rcmail_get_edit_field($col, $val, $colprop, $colprop['type']); |
| | |
| | | function rcmail_format_date_col($val) |
| | | { |
| | | global $RCMAIL; |
| | | return format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d')); |
| | | return format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d'), false); |
| | | } |
| | | |
| | | |
| | |
| | | foreach ($cid as $id) { |
| | | // if _source is not specified we'll find it from decoded ID |
| | | if (!$got_source) { |
| | | list ($c, $s) = explode('-', $id, 2); |
| | | if (strlen($s)) { |
| | | $result[(string)$s][] = $c; |
| | | if ($sep = strrpos($id, '-')) { |
| | | $contact_id = substr($id, 0, $sep); |
| | | $source_id = substr($id, $sep+1); |
| | | if (strlen($source_id)) { |
| | | $result[(string)$source_id][] = $contact_id; |
| | | } |
| | | } |
| | | } |
| | | else { |
| | |
| | | $members[] = format_email_recipient($email, $sql_arr['name']); |
| | | } |
| | | |
| | | $OUTPUT->command('replace_group_recipients', $gid, join(', ', $members)); |
| | | $separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' '; |
| | | $OUTPUT->command('replace_group_recipients', $gid, join($separator, array_unique($members))); |
| | | } |
| | | |
| | | $OUTPUT->send(); |
| | |
| | | if ($email_cnt > 1 && stripos($contact, $search) === false) { |
| | | continue; |
| | | } |
| | | // when we've got more than one book, we need to skip duplicates |
| | | if ($books_num == 1 || !in_array($contact, $contacts)) { |
| | | // skip duplicates |
| | | if (!in_array($contact, $contacts)) { |
| | | $contacts[] = $contact; |
| | | if (count($contacts) >= $MAXNUM) |
| | | break 2; |
| | |
| | | | program/steps/mail/compose.inc | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2009, The Roundcube Dev Team | |
| | | | Copyright (C) 2005-2011, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | } |
| | | // set current mailbox in client environment |
| | | $OUTPUT->set_env('mailbox', $IMAP->get_mailbox_name()); |
| | | $OUTPUT->set_env('sig_above', $CONFIG['sig_above']); |
| | | $OUTPUT->set_env('top_posting', $CONFIG['top_posting']); |
| | | $OUTPUT->set_env('sig_above', $RCMAIL->config->get('sig_above', false)); |
| | | $OUTPUT->set_env('top_posting', $RCMAIL->config->get('top_posting', false)); |
| | | $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); |
| | | |
| | | // get reference message and set compose mode |
| | | if ($msg_uid = $_SESSION['compose']['param']['draft_uid']) { |
| | |
| | | // Set other headers |
| | | $a_recipients = array(); |
| | | $parts = array('to', 'cc', 'bcc', 'replyto', 'followupto'); |
| | | $separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' '; |
| | | |
| | | foreach ($parts as $header) { |
| | | $fvalue = ''; |
| | |
| | | if ($v = $MESSAGE->headers->to) |
| | | $fvalue .= $v; |
| | | if ($v = $MESSAGE->headers->cc) |
| | | $fvalue .= (!empty($fvalue) ? ', ' : '') . $v; |
| | | $fvalue .= (!empty($fvalue) ? $separator : '') . $v; |
| | | } |
| | | } |
| | | else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { |
| | |
| | | } |
| | | } |
| | | |
| | | $fvalue = implode(', ', $fvalue); |
| | | $fvalue = implode($separator, $fvalue); |
| | | } |
| | | |
| | | $MESSAGE->compose[$header] = $fvalue; |
| | |
| | | |
| | | // previous line is flowed? |
| | | if (isset($body[$last]) && $body[$n] |
| | | && $last != $last_sig |
| | | && $last !== $last_sig |
| | | && $body[$last][strlen($body[$last])-1] == ' ' |
| | | ) { |
| | | $body[$last] .= $body[$n]; |
| | |
| | | | program/steps/mail/sendmail.inc | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2010, The Roundcube Dev Team | |
| | | | Copyright (C) 2005-2011, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | return $body; |
| | | } |
| | | |
| | | // parse email address input (and count addresses) |
| | | /** |
| | | * Parse and cleanup email address input (and count addresses) |
| | | * |
| | | * @param string Address input |
| | | * @param boolean Do count recipients (saved in global $RECIPIENT_COUNT) |
| | | * @param boolean Validate addresses (errors saved in global $EMAIL_FORMAT_ERROR) |
| | | * @return string Canonical recipients string separated by comma |
| | | */ |
| | | function rcmail_email_input_format($mailto, $count=false, $check=true) |
| | | { |
| | | global $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT; |
| | | global $RCMAIL, $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT; |
| | | |
| | | // simplified email regexp, supporting quoted local part |
| | | $email_regexp = '(\S+|("[^"]+"))@\S+'; |
| | | |
| | | $regexp = array('/[,;]\s*[\r\n]+/', '/[\r\n]+/', '/[,;]\s*$/m', '/;/', '/(\S{1})(<'.$email_regexp.'>)/U'); |
| | | $replace = array(', ', ', ', '', ',', '\\1 \\2'); |
| | | $delim = trim($RCMAIL->config->get('recipients_separator', ',')); |
| | | $regexp = array("/[,;$delim]\s*[\r\n]+/", '/[\r\n]+/', "/[,;$delim]\s*\$/m", '/;/', '/(\S{1})(<'.$email_regexp.'>)/U'); |
| | | $replace = array($delim.' ', ', ', '', $delim, '\\1 \\2'); |
| | | |
| | | // replace new lines and strip ending ', ', make address input more valid |
| | | $mailto = trim(preg_replace($regexp, $replace, $mailto)); |
| | | |
| | | $result = array(); |
| | | $items = rcube_explode_quoted_string(',', $mailto); |
| | | $items = rcube_explode_quoted_string($delim, $mailto); |
| | | |
| | | foreach($items as $item) { |
| | | $item = trim($item); |
| | |
| | | // address with name (handle name) |
| | | } else if (preg_match('/<*'.$email_regexp.'>*$/', $item, $matches)) { |
| | | $address = $matches[0]; |
| | | $name = str_replace($address, '', $item); |
| | | $name = trim($name); |
| | | if ($name && ($name[0] != '"' || $name[strlen($name)-1] != '"') |
| | | && preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name)) { |
| | | $name = '"'.addcslashes($name, '"').'"'; |
| | | } |
| | | $name = trim(str_replace($address, '', $item), '" '); |
| | | $address = rcube_idn_to_ascii(trim($address, '<>')); |
| | | $address = '<' . $address . '>'; |
| | | |
| | | $result[] = $name.' '.$address; |
| | | $result[] = format_email_recipient($address, $name); |
| | | $item = $address; |
| | | } else if (trim($item)) { |
| | | continue; |
| | |
| | | 'realnames' => false, |
| | | 'maxlength' => 150, |
| | | 'unsubscribed' => true, |
| | | 'exceptions' => array($mbox_imap), |
| | | 'skip_noinferiors' => true, |
| | | 'exceptions' => array($mbox_imap), |
| | | )); |
| | | |
| | | $form['props']['fieldsets']['location']['content']['path'] = array( |
| | |
| | | } |
| | | |
| | | if (!$protected) { |
| | | $opts = $IMAP->mailbox_options($folder['id']); |
| | | $noselect = in_array('\\Noselect', $opts); |
| | | $attrs = $IMAP->mailbox_attributes($folder['id']); |
| | | $noselect = in_array('\\Noselect', $attrs); |
| | | } |
| | | |
| | | $disabled = (($protected && $subscribed) || $noselect); |