Merge branch devel-addressbook (r4193:4382) back into trunk
1 files added
38 files modified
| | |
| | | // mime magic database |
| | | $rcmail_config['mime_magic'] = '/usr/share/misc/magic'; |
| | | |
| | | // path to imagemagick identify binary |
| | | $rcmail_config['im_identify_path'] = null; |
| | | |
| | | // path to imagemagick convert binary |
| | | $rcmail_config['im_convert_path'] = null; |
| | | |
| | | // maximum size of uploaded contact photos in pixel |
| | | $rcmail_config['contact_photo_size'] = 160; |
| | | |
| | | // Enable DNS checking for e-mail address validation |
| | | $rcmail_config['email_dns_check'] = false; |
| | | |
| | |
| | | |
| | | // use this format for today's date display (date or strftime format) |
| | | $rcmail_config['date_today'] = 'H:i'; |
| | | |
| | | // use this format for date display without time (date or strftime format) |
| | | $rcmail_config['date_format'] = 'Y-m-d'; |
| | | |
| | | // store draft message is this mailbox |
| | | // leave blank if draft messages should not be stored |
| | |
| | | // The login name is used to search for the DN to bind with |
| | | 'search_base_dn' => '', |
| | | 'search_filter' => '', // e.g. '(&(objectClass=posixAccount)(uid=%u))' |
| | | |
| | | 'writable' => false, // Indicates if we can write to the LDAP directory or not. |
| | | // If writable is true then these fields need to be populated: |
| | | // LDAP_Object_Classes, required_fields, LDAP_rdn |
| | |
| | | 'LDAP_rdn' => 'mail', // The RDN field that is used for new entries, this field needs to be one of the search_fields, the base of base_dn is appended to the RDN to insert into the LDAP directory. |
| | | 'ldap_version' => 3, // using LDAPv3 |
| | | 'search_fields' => array('mail', 'cn'), // fields to search in |
| | | 'name_field' => 'cn', // this field represents the contact's name |
| | | 'email_field' => 'mail', // this field represents the contact's e-mail |
| | | 'surname_field' => 'sn', // this field represents the contact's last name |
| | | 'firstname_field' => 'gn', // this field represents the contact's first name |
| | | 'fieldmap' => array( // mapping of contact fields to directory attributes |
| | | // Roundcube => LDAP |
| | | 'name' => 'cn', |
| | | 'surname' => 'sn', |
| | | 'firstname' => 'givenName', |
| | | 'email' => 'mail', |
| | | 'phone:home' => 'homePhone', |
| | | 'phone:work' => 'telephoneNumber', |
| | | 'phone:mobile' => 'mobile', |
| | | 'street' => 'street', |
| | | 'zipcode' => 'postalCode', |
| | | 'locality' => 'l', |
| | | 'country' => 'c', |
| | | 'organization' => 'o', |
| | | ), |
| | | 'sort' => 'cn', // The field to sort the listing by. |
| | | 'scope' => 'sub', // search mode: sub|base|list |
| | | 'filter' => '', // used for basic listing (if not empty) and will be &'d with search queries. example: status=act |
| | |
| | | // may need to do lengthy results building given overly-broad searches |
| | | $rcmail_config['autocomplete_min_length'] = 1; |
| | | |
| | | // show address fields in this order |
| | | // available placeholders: {street}, {locality}, {zipcode}, {country}, {region} |
| | | $rcmail_config['address_template'] = '{street}<br/>{locality} {zipcode}<br/>{country} {region}'; |
| | | |
| | | // ---------------------------------- |
| | | // USER PREFERENCES |
| | | // ---------------------------------- |
| | |
| | | */ |
| | | public static function tag($tagname, $attrib = array(), $content = null, $allowed_attrib = null) |
| | | { |
| | | if (is_string($attrib)) |
| | | $attrib = array('class' => $attrib); |
| | | |
| | | $inline_tags = array('a','span','img'); |
| | | $suffix = $attrib['nl'] || ($content && $attrib['nl'] !== false && !in_array($tagname, $inline_tags)) ? "\n" : ''; |
| | | |
| | |
| | | $attr = array('href' => $attr); |
| | | } |
| | | return self::tag('a', $attr, $cont, array_merge(self::$common_attrib, |
| | | array('href','target','name','onclick','onmouseover','onmouseout','onmousedown','onmouseup'))); |
| | | array('href','target','name','rel','onclick','onmouseover','onmouseout','onmousedown','onmouseup'))); |
| | | } |
| | | |
| | | /** |
| | |
| | | protected $tagname = 'select'; |
| | | protected $options = array(); |
| | | protected $allowed = array('name','size','tabindex','autocomplete', |
| | | 'multiple','onchange','disabled'); |
| | | 'multiple','onchange','disabled','rel'); |
| | | |
| | | /** |
| | | * Add a new option to this drop-down |
| | |
| | | |
| | | // format each col |
| | | foreach ($a_show_cols as $col) |
| | | $table->add($col, Q($row_data[$col])); |
| | | $table->add($col, Q(is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col])); |
| | | |
| | | $c++; |
| | | } |
| | |
| | | */ |
| | | function rcmail_get_edit_field($col, $value, $attrib, $type='text') |
| | | { |
| | | $fname = '_'.$col; |
| | | $attrib['name'] = $fname; |
| | | static $colcounts = array(); |
| | | |
| | | if ($type=='checkbox') |
| | | { |
| | | $fname = '_'.$col; |
| | | $attrib['name'] = $fname . ($attrib['array'] ? '[]' : ''); |
| | | $attrib['class'] = trim($attrib['class'] . ' ff_' . $col); |
| | | |
| | | if ($type == 'checkbox') { |
| | | $attrib['value'] = '1'; |
| | | $input = new html_checkbox($attrib); |
| | | } |
| | | else if ($type=='textarea') |
| | | { |
| | | else if ($type == 'textarea') { |
| | | $attrib['cols'] = $attrib['size']; |
| | | $input = new html_textarea($attrib); |
| | | } |
| | | else |
| | | else if ($type == 'select') { |
| | | $input = new html_select($attrib); |
| | | $input->add('---', ''); |
| | | $input->add(array_values($attrib['options']), array_keys($attrib['options'])); |
| | | } |
| | | else { |
| | | if ($attrib['type'] != 'text' && $attrib['type'] != 'hidden') |
| | | $attrib['type'] = 'text'; |
| | | $input = new html_inputfield($attrib); |
| | | } |
| | | |
| | | // use value from post |
| | | if (!empty($_POST[$fname])) |
| | | $value = get_input_value($fname, RCUBE_INPUT_POST, |
| | | if (isset($_POST[$fname])) { |
| | | $postvalue = get_input_value($fname, RCUBE_INPUT_POST, |
| | | $type == 'textarea' && strpos($attrib['class'], 'mce_editor')!==false ? true : false); |
| | | $value = $attrib['array'] ? $postvalue[intval($colcounts[$col]++)] : $postvalue; |
| | | } |
| | | |
| | | $out = $input->show($value); |
| | | |
| | |
| | | public $comm_path = './'; |
| | | |
| | | private $texts; |
| | | private $books = array(); |
| | | private $address_books = array(); |
| | | private $action_map = array(); |
| | | |
| | | |
| | |
| | | if ($plugin['instance'] instanceof rcube_addressbook) { |
| | | $contacts = $plugin['instance']; |
| | | } |
| | | // use existing instance |
| | | else if (isset($this->address_books[$id]) && is_a($this->address_books[$id], 'rcube_addressbook') && (!$writeable || !$this->address_books[$id]->readonly)) { |
| | | $contacts = $this->address_books[$id]; |
| | | } |
| | | else if ($id && $ldap_config[$id]) { |
| | | $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host'])); |
| | | } |
| | |
| | | } |
| | | |
| | | // add to the 'books' array for shutdown function |
| | | if (!in_array($contacts, $this->books)) |
| | | $this->books[] = $contacts; |
| | | if (!isset($this->address_books[$id])) |
| | | $this->address_books[$id] = $contacts; |
| | | |
| | | return $contacts; |
| | | } |
| | |
| | | |
| | | // We are using the DB address book |
| | | if ($abook_type != 'ldap') { |
| | | $contacts = new rcube_contacts($this->db, null); |
| | | if (!isset($this->address_books['0'])) |
| | | $this->address_books['0'] = new rcube_contacts($this->db, $this->user->ID); |
| | | $list['0'] = array( |
| | | 'id' => 0, |
| | | 'id' => '0', |
| | | 'name' => rcube_label('personaladrbook'), |
| | | 'groups' => $contacts->groups, |
| | | 'groups' => $this->address_books['0']->groups, |
| | | 'readonly' => false, |
| | | 'autocomplete' => in_array('sql', $autocomplete) |
| | | ); |
| | |
| | | $plugin = $this->plugins->exec_hook('addressbooks_list', array('sources' => $list)); |
| | | $list = $plugin['sources']; |
| | | |
| | | if ($writeable && !empty($list)) { |
| | | foreach ($list as $idx => $item) { |
| | | if ($item['readonly']) { |
| | | // register source for shutdown function |
| | | if (!is_object($this->address_books[$item['id']])) |
| | | $this->address_books[$item['id']] = $item; |
| | | // remove from list if not writeable as requested |
| | | if ($writeable && $item['readonly']) |
| | | unset($list[$idx]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return $list; |
| | |
| | | if (is_object($this->smtp)) |
| | | $this->smtp->disconnect(); |
| | | |
| | | foreach ($this->books as $book) |
| | | if (is_object($book)) |
| | | foreach ($this->address_books as $book) { |
| | | if (!is_object($book)) // maybe an address book instance wasn't fetched using get_address_book() yet |
| | | $book = $this->get_address_book($book['id']); |
| | | if (is_a($book, 'rcube_addressbook')) |
| | | $book->close(); |
| | | } |
| | | |
| | | // before closing the database connection, write session data |
| | | if ($_SERVER['REMOTE_ADDR']) |
| | |
| | | |
| | | |
| | | /** |
| | | * Use imagemagick or GD lib to read image properties |
| | | * |
| | | * @param string Absolute file path |
| | | * @return mixed Hash array with image props like type, width, height or False on error |
| | | */ |
| | | public static function imageprops($filepath) |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | if ($cmd = $rcmail->config->get('im_identify_path', false)) { |
| | | list(, $type, $size) = explode(' ', strtolower(rcmail::exec($cmd. ' 2>/dev/null {in}', array('in' => $filepath)))); |
| | | if ($size) |
| | | list($width, $height) = explode('x', $size); |
| | | } |
| | | else if (function_exists('getimagesize')) { |
| | | $imsize = @getimagesize($filepath); |
| | | $width = $imsize[0]; |
| | | $height = $imsize[1]; |
| | | $type = preg_replace('!image/!', '', $imsize['mime']); |
| | | } |
| | | |
| | | return $type ? array('type' => $type, 'width' => $width, 'height' => $height) : false; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Convert an image to a given size and type using imagemagick (ensures input is an image) |
| | | * |
| | | * @param $p['in'] Input filename (mandatory) |
| | | * @param $p['out'] Output filename (mandatory) |
| | | * @param $p['size'] Width x height of resulting image, e.g. "160x60" |
| | | * @param $p['type'] Output file type, e.g. "jpg" |
| | | * @param $p['-opts'] Custom command line options to ImageMagick convert |
| | | * @return Success of convert as true/false |
| | | */ |
| | | public static function imageconvert($p) |
| | | { |
| | | $result = false; |
| | | $rcmail = rcmail::get_instance(); |
| | | $convert = $rcmail->config->get('im_convert_path', false); |
| | | $identify = $rcmail->config->get('im_identify_path', false); |
| | | |
| | | // imagemagick is required for this |
| | | if (!$convert) |
| | | return false; |
| | | |
| | | if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false)))) |
| | | list(, $type) = explode(' ', strtolower(rcmail::exec($identify . ' 2>/dev/null {in}', $p))); # for things like eps |
| | | |
| | | $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps")); |
| | | $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75); |
| | | $p['-opts'] = array('-resize' => $p['size'].'>') + (array)$p['-opts']; |
| | | |
| | | if (in_array($type, explode(',', $p['types']))) # Valid type? |
| | | $result = rcmail::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === ""; |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Construct shell command, execute it and return output as string. |
| | | * Keywords {keyword} are replaced with arguments |
| | | * |
| | | * @param $cmd Format string with {keywords} to be replaced |
| | | * @param $values (zero, one or more arrays can be passed) |
| | | * @return output of command. shell errors not detectable |
| | | */ |
| | | public static function exec(/* $cmd, $values1 = array(), ... */) |
| | | { |
| | | $args = func_get_args(); |
| | | $cmd = array_shift($args); |
| | | $values = $replacements = array(); |
| | | |
| | | // merge values into one array |
| | | foreach ($args as $arg) |
| | | $values += (array)$arg; |
| | | |
| | | preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER); |
| | | foreach ($matches as $tags) { |
| | | list(, $tag, $option, $key) = $tags; |
| | | $parts = array(); |
| | | |
| | | if ($option) { |
| | | foreach ((array)$values["-$key"] as $key => $value) { |
| | | if ($value === true || $value === false || $value === null) |
| | | $parts[] = $value ? $key : ""; |
| | | else foreach ((array)$value as $val) |
| | | $parts[] = "$key " . escapeshellarg($val); |
| | | } |
| | | } |
| | | else { |
| | | foreach ((array)$values[$key] as $value) |
| | | $parts[] = escapeshellarg($value); |
| | | } |
| | | |
| | | $replacements[$tag] = join(" ", $parts); |
| | | } |
| | | |
| | | // use strtr behaviour of going through source string once |
| | | $cmd = strtr($cmd, $replacements); |
| | | |
| | | return (string)shell_exec($cmd); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Helper method to set a cookie with the current path and host settings |
| | | * |
| | | * @param string Cookie name |
| | |
| | | | program/include/rcube_addressbook.php | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2006-2009, The Roundcube Dev Team | |
| | | | Copyright (C) 2006-2011, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | */ |
| | | abstract class rcube_addressbook |
| | | { |
| | | /** public properties */ |
| | | var $primary_key; |
| | | var $groups = false; |
| | | var $readonly = true; |
| | | var $ready = false; |
| | | var $list_page = 1; |
| | | var $page_size = 10; |
| | | /** constants for error reporting **/ |
| | | const ERROR_READ_ONLY = 1; |
| | | const ERROR_NO_CONNECTION = 2; |
| | | const ERROR_INCOMPLETE = 3; |
| | | const ERROR_SAVING = 4; |
| | | |
| | | /** public properties (mandatory) */ |
| | | public $primary_key; |
| | | public $groups = false; |
| | | public $readonly = true; |
| | | public $ready = false; |
| | | public $list_page = 1; |
| | | public $page_size = 10; |
| | | public $coltypes = array('name' => array('limit'=>1), 'firstname' => array('limit'=>1), 'surname' => array('limit'=>1), 'email' => array('limit'=>1)); |
| | | |
| | | protected $error; |
| | | |
| | | /** |
| | | * Save a search string for future listings |
| | |
| | | abstract function reset(); |
| | | |
| | | /** |
| | | * Refresh saved search set after data has changed |
| | | * |
| | | * @return mixed New search set |
| | | */ |
| | | function refresh_search() |
| | | { |
| | | return $this->get_search_set(); |
| | | } |
| | | |
| | | /** |
| | | * List the current set of contact records |
| | | * |
| | | * @param array List of cols to show |
| | |
| | | * @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 |
| | | * @param boolean True to skip the count query (select only) |
| | | * @param array List of fields that cannot be empty |
| | | * @return object rcube_result_set List of contact records and 'count' value |
| | | */ |
| | | abstract function search($fields, $value, $strict=false, $select=true); |
| | | abstract function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()); |
| | | |
| | | /** |
| | | * Count number of available contacts in database |
| | |
| | | * @return mixed Result object with all record fields or False if not found |
| | | */ |
| | | abstract function get_record($id, $assoc=false); |
| | | |
| | | /** |
| | | * Returns the last error occured (e.g. when updating/inserting failed) |
| | | * |
| | | * @return array Hash array with the following fields: type, message |
| | | */ |
| | | function get_error() |
| | | { |
| | | return $this->error; |
| | | } |
| | | |
| | | /** |
| | | * Setter for errors for internal use |
| | | * |
| | | * @param int Error type (one of this class' error constants) |
| | | * @param string Error message (name of a text label) |
| | | */ |
| | | protected function set_error($type, $message) |
| | | { |
| | | $this->error = array('type' => $type, 'message' => $message); |
| | | } |
| | | |
| | | /** |
| | | * Close connection to source |
| | |
| | | * Create a new contact record |
| | | * |
| | | * @param array Assoziative array with save data |
| | | * Keys: Field name with optional section in the form FIELD:SECTION |
| | | * Values: Field value. Can be either a string or an array of strings for multiple values |
| | | * @param boolean True to check for duplicates first |
| | | * @return mixed The created record ID on success, False on error |
| | | */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * Create new contact records for every item in the record set |
| | | * |
| | | * @param object rcube_result_set Recordset to insert |
| | | * @param boolean True to check for duplicates first |
| | | * @return array List of created record IDs |
| | | */ |
| | | function insertMultiple($recset, $check=false) |
| | | { |
| | | $ids = array(); |
| | | if (is_object($recset) && is_a($recset, rcube_result_set)) { |
| | | while ($row = $recset->next()) { |
| | | if ($insert = $this->insert($row, $check)) |
| | | $ids[] = $insert; |
| | | } |
| | | } |
| | | return $ids; |
| | | } |
| | | |
| | | /** |
| | | * Update a specific contact record |
| | | * |
| | | * @param mixed Record identifier |
| | | * @param array Assoziative array with save data |
| | | * Keys: Field name with optional section in the form FIELD:SECTION |
| | | * Values: Field value. Can be either a string or an array of strings for multiple values |
| | | * @return boolean True on success, False on error |
| | | */ |
| | | function update($id, $save_cols) |
| | |
| | | /** |
| | | * List all active contact groups of this source |
| | | * |
| | | * @param string Optional search string to match group name |
| | | * @return array Indexed list of contact groups, each a hash array |
| | | */ |
| | | function list_groups() |
| | | function list_groups($search = null) |
| | | { |
| | | /* empty for address books don't supporting groups */ |
| | | return array(); |
| | |
| | | /* empty for address books don't supporting groups */ |
| | | return array(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Utility function to return all values of a certain data column |
| | | * either as flat list or grouped by subtype |
| | | * |
| | | * @param string Col name |
| | | * @param array Record data array as used for saving |
| | | * @param boolean True to return one array with all values, False for hash array with values grouped by type |
| | | * @return array List of column values |
| | | */ |
| | | function get_col_values($col, $data, $flat = false) |
| | | { |
| | | $out = array(); |
| | | foreach ($data as $c => $values) { |
| | | if (strpos($c, $col) === 0) { |
| | | if ($flat) { |
| | | $out = array_merge($out, (array)$values); |
| | | } |
| | | else { |
| | | list($f, $type) = explode(':', $c); |
| | | $out[$type] = array_merge((array)$out[$type], (array)$values); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | } |
| | | |
| | |
| | | $this->dom = ($this->mz || $this->safari || ($this->ie && $this->ver>=5) || ($this->opera && $this->ver>=7)); |
| | | $this->pngalpha = $this->mz || $this->safari || ($this->ie && $this->ver>=5.5) || |
| | | ($this->ie && $this->ver>=5 && $this->mac) || ($this->opera && $this->ver>=7) ? true : false; |
| | | $this->imgdata = !$this->ie; |
| | | } |
| | | } |
| | | |
| | |
| | | private $table_cols = array('name', 'email', 'firstname', 'surname', 'vcard'); |
| | | |
| | | // public properties |
| | | var $primary_key = 'contact_id'; |
| | | var $readonly = false; |
| | | var $groups = true; |
| | | var $list_page = 1; |
| | | var $page_size = 10; |
| | | var $group_id = 0; |
| | | var $ready = false; |
| | | public $primary_key = 'contact_id'; |
| | | public $readonly = false; |
| | | public $groups = true; |
| | | public $list_page = 1; |
| | | public $page_size = 10; |
| | | public $group_id = 0; |
| | | public $ready = false; |
| | | public $coltypes = array('name', 'firstname', 'surname', 'middlename', 'prefix', 'suffix', 'nickname', |
| | | 'jobtitle', 'organization', 'department', 'assistant', 'manager', |
| | | 'gender', 'maidenname', 'spouse', 'email', 'phone', 'address', |
| | | 'birthday', 'anniversary', 'website', 'im', 'notes', 'photo'); |
| | | |
| | | |
| | | /** |
| | |
| | | /** |
| | | * List the current set of contact records |
| | | * |
| | | * @param array List of cols to show |
| | | * @param array List of cols to show, Null means all |
| | | * @param int Only return this number of records, use negative values for tail |
| | | * @param boolean True to skip the count query (select only) |
| | | * @return array Indexed list of contact records, each a hash array |
| | |
| | | $this->user_id, |
| | | $this->group_id); |
| | | |
| | | // determine whether we have to parse the vcard or if only db cols are requested |
| | | $read_vcard = !$cols || count(array_intersect($cols, $this->table_cols)) < count($cols); |
| | | |
| | | while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { |
| | | $sql_arr['ID'] = $sql_arr[$this->primary_key]; |
| | | |
| | | if ($read_vcard) |
| | | $sql_arr = $this->convert_db_data($sql_arr); |
| | | else |
| | | $sql_arr['email'] = preg_split('/,\s*/', $sql_arr['email']); |
| | | |
| | | // make sure we have a name to display |
| | | if (empty($sql_arr['name'])) |
| | | $sql_arr['name'] = $sql_arr['email']; |
| | | $sql_arr['name'] = $sql_arr['email'][0]; |
| | | |
| | | $this->result->add($sql_arr); |
| | | } |
| | | |
| | |
| | | * @param boolean True if results are requested, False if count only |
| | | * @param boolean True to skip the count query (select only) |
| | | * @param array List of fields that cannot be empty |
| | | * @return Indexed list of contact records and 'count' value |
| | | * @return object rcube_result_set Contact records and 'count' value |
| | | */ |
| | | function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()) |
| | | { |
| | |
| | | ); |
| | | |
| | | if ($sql_arr = $this->db->fetch_assoc()) { |
| | | $sql_arr['ID'] = $sql_arr[$this->primary_key]; |
| | | $record = $this->convert_db_data($sql_arr); |
| | | $this->result = new rcube_result_set(1); |
| | | $this->result->add($sql_arr); |
| | | $this->result->add($record); |
| | | } |
| | | |
| | | return $assoc && $sql_arr ? $sql_arr : $this->result; |
| | | return $assoc && $record ? $record : $this->result; |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | function insert($save_data, $check=false) |
| | | { |
| | | if (is_object($save_data) && is_a($save_data, rcube_result_set)) |
| | | return $this->insert_recset($save_data, $check); |
| | | if (!is_array($save_data)) |
| | | return false; |
| | | |
| | | $insert_id = $existing = false; |
| | | |
| | | if ($check) |
| | | $existing = $this->search('email', $save_data['email'], true, false); |
| | | if ($check) { |
| | | foreach ($save_data as $col => $values) { |
| | | if (strpos($col, 'email') === 0) { |
| | | foreach ((array)$values as $email) { |
| | | if ($existing = $this->search('email', $email, true, false)) |
| | | break 2; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | $save_data = $this->convert_save_data($save_data); |
| | | $a_insert_cols = $a_insert_values = array(); |
| | | |
| | | foreach ($this->table_cols as $col) |
| | | if (isset($save_data[$col])) { |
| | | foreach ($save_data as $col => $value) { |
| | | $a_insert_cols[] = $this->db->quoteIdentifier($col); |
| | | $a_insert_values[] = $this->db->quote($save_data[$col]); |
| | | $a_insert_values[] = $this->db->quote($value); |
| | | } |
| | | |
| | | if (!$existing->count && !empty($a_insert_cols)) { |
| | |
| | | |
| | | |
| | | /** |
| | | * Insert new contacts for each row in set |
| | | */ |
| | | function insert_recset($result, $check=false) |
| | | { |
| | | $ids = array(); |
| | | while ($row = $result->next()) { |
| | | if ($insert = $this->insert($row, $check)) |
| | | $ids[] = $insert; |
| | | } |
| | | return $ids; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Update a specific contact record |
| | | * |
| | | * @param mixed Record identifier |
| | |
| | | { |
| | | $updated = false; |
| | | $write_sql = array(); |
| | | $record = $this->get_record($id, true); |
| | | $save_cols = $this->convert_save_data($save_cols, $record); |
| | | |
| | | foreach ($this->table_cols as $col) |
| | | if (isset($save_cols[$col])) |
| | | $write_sql[] = sprintf("%s=%s", $this->db->quoteIdentifier($col), |
| | | $this->db->quote($save_cols[$col])); |
| | | foreach ($save_cols as $col => $value) { |
| | | $write_sql[] = sprintf("%s=%s", $this->db->quoteIdentifier($col), $this->db->quote($value)); |
| | | } |
| | | |
| | | if (!empty($write_sql)) { |
| | | $this->db->query( |
| | |
| | | ); |
| | | |
| | | $updated = $this->db->affected_rows(); |
| | | $this->result = null; // clear current result (from get_record()) |
| | | } |
| | | |
| | | return $updated; |
| | | } |
| | | |
| | | |
| | | private function convert_db_data($sql_arr) |
| | | { |
| | | $record = array(); |
| | | $record['ID'] = $sql_arr[$this->primary_key]; |
| | | |
| | | if ($sql_arr['vcard']) { |
| | | unset($sql_arr['email']); |
| | | $vcard = new rcube_vcard($sql_arr['vcard']); |
| | | $record += $vcard->get_assoc() + $sql_arr; |
| | | } |
| | | else { |
| | | $record += $sql_arr; |
| | | $record['email'] = preg_split('/,\s*/', $record['email']); |
| | | } |
| | | |
| | | return $record; |
| | | } |
| | | |
| | | |
| | | private function convert_save_data($save_data, $record = array()) |
| | | { |
| | | $out = array(); |
| | | |
| | | // copy values into vcard object |
| | | $vcard = new rcube_vcard($record['vcard'] ? $record['vcard'] : $save_data['vcard']); |
| | | $vcard->reset(); |
| | | foreach ($save_data as $key => $values) { |
| | | list($field, $section) = explode(':', $key); |
| | | foreach ((array)$values as $value) { |
| | | if (isset($value)) |
| | | $vcard->set($field, $value, $section); |
| | | } |
| | | } |
| | | $out['vcard'] = $vcard->export(); |
| | | |
| | | foreach ($this->table_cols as $col) { |
| | | $key = $col; |
| | | if (!isset($save_data[$key])) |
| | | $key .= ':home'; |
| | | if (isset($save_data[$key])) |
| | | $out[$col] = is_array($save_data[$key]) ? join(',', $save_data[$key]) : $save_data[$key]; |
| | | } |
| | | |
| | | // save all e-mails in database column |
| | | $out['email'] = join(", ", $vcard->email); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Mark one or more contact records as deleted |
| | | * |
| | |
| | | */ |
| | | class rcube_ldap extends rcube_addressbook |
| | | { |
| | | var $conn; |
| | | var $prop = array(); |
| | | var $fieldmap = array(); |
| | | protected $conn; |
| | | protected $prop = array(); |
| | | protected $fieldmap = array(); |
| | | |
| | | var $filter = ''; |
| | | var $result = null; |
| | | var $ldap_result = null; |
| | | var $sort_col = ''; |
| | | var $mail_domain = ''; |
| | | var $debug = false; |
| | | protected $filter = ''; |
| | | protected $result = null; |
| | | protected $ldap_result = null; |
| | | protected $sort_col = ''; |
| | | protected $mail_domain = ''; |
| | | protected $debug = false; |
| | | |
| | | /** public properties */ |
| | | var $primary_key = 'ID'; |
| | | var $readonly = true; |
| | | var $list_page = 1; |
| | | var $page_size = 10; |
| | | var $ready = false; |
| | | public $primary_key = 'ID'; |
| | | public $readonly = true; |
| | | public $list_page = 1; |
| | | public $page_size = 10; |
| | | public $ready = false; |
| | | public $coltypes = array(); |
| | | |
| | | |
| | | /** |
| | |
| | | { |
| | | $this->prop = $p; |
| | | |
| | | // fieldmap property is given |
| | | if (is_array($p['fieldmap'])) { |
| | | foreach ($p['fieldmap'] as $rf => $lf) |
| | | $this->fieldmap[$rf] = $this->_attr_name(strtolower($lf)); |
| | | } |
| | | else { |
| | | // read deprecated *_field properties to remain backwards compatible |
| | | foreach ($p as $prop => $value) |
| | | if (preg_match('/^(.+)_field$/', $prop, $matches)) |
| | | $this->fieldmap[$matches[1]] = $this->_attr_name(strtolower($value)); |
| | | } |
| | | |
| | | // use fieldmap to advertise supported coltypes to the application |
| | | foreach ($this->fieldmap as $col => $lf) { |
| | | list($col, $type) = explode(':', $col); |
| | | if (!is_array($this->coltypes[$col])) { |
| | | $subtypes = $type ? array($type) : null; |
| | | $this->coltypes[$col] = array('limit' => 2, 'subtypes' => $subtypes); |
| | | } |
| | | else if ($type) { |
| | | $this->coltypes[$col]['subtypes'][] = $type; |
| | | $this->coltypes[$col]['limit']++; |
| | | } |
| | | if ($type && !$this->fieldmap[$col]) |
| | | $this->fieldmap[$col] = $lf; |
| | | } |
| | | |
| | | if ($this->fieldmap['street'] && $this->fieldmap['locality']) |
| | | $this->coltypes['address'] = array('limit' => 1); |
| | | else if ($this->coltypes['address']) |
| | | $this->coltypes['address'] = array('type' => 'textarea', 'childs' => null, 'limit' => 1, 'size' => 40); |
| | | |
| | | // make sure 'required_fields' is an array |
| | | if (!is_array($this->prop['required_fields'])) |
| | |
| | | |
| | | if ($entry && ($rec = ldap_get_attributes($this->conn, $entry))) |
| | | { |
| | | $this->_debug("S: OK"); |
| | | $this->_debug("S: OK"/* . print_r($rec, true)*/); |
| | | |
| | | $rec = array_change_key_case($rec, CASE_LOWER); |
| | | |
| | |
| | | // Map out the column names to their LDAP ones to build the new entry. |
| | | $newentry = array(); |
| | | $newentry['objectClass'] = $this->prop['LDAP_Object_Classes']; |
| | | foreach ($save_cols as $col => $val) { |
| | | $fld = $this->_map_field($col); |
| | | foreach ($this->fieldmap as $col => $fld) { |
| | | $val = $save_cols[$col]; |
| | | if (is_array($val)) |
| | | $val = array_filter($val); // remove empty entries |
| | | if ($fld && $val) { |
| | | // The field does exist, add it to the entry. |
| | | $newentry[$fld] = $val; |
| | |
| | | } // end foreach |
| | | |
| | | // Verify that the required fields are set. |
| | | // We know that the email address is required as a default of rcube, so |
| | | // we will default its value into any unfilled required fields. |
| | | foreach ($this->prop['required_fields'] as $fld) { |
| | | $missing = null; |
| | | if (!isset($newentry[$fld])) { |
| | | $newentry[$fld] = $newentry[$this->_map_field('email')]; |
| | | } // end if |
| | | } // end foreach |
| | | $missing[] = $fld; |
| | | } |
| | | } |
| | | |
| | | // abort process if requiered fields are missing |
| | | // TODO: generate message saying which fields are missing |
| | | if ($missing) { |
| | | $this->set_error(self::ERROR_INCOMPLETE, 'formincomplete'); |
| | | return false; |
| | | } |
| | | |
| | | // Build the new entries DN. |
| | | $dn = $this->prop['LDAP_rdn'].'='.rcube_ldap::quote_string($newentry[$this->prop['LDAP_rdn']], true) |
| | | .','.$this->prop['base_dn']; |
| | | $dn = $this->prop['LDAP_rdn'].'='.rcube_ldap::quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->prop['base_dn']; |
| | | |
| | | $this->_debug("C: Add [dn: $dn]: ".print_r($newentry, true)); |
| | | |
| | | $res = ldap_add($this->conn, $dn, $newentry); |
| | | if ($res === FALSE) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } // end if |
| | | |
| | |
| | | $newdata = array(); |
| | | $replacedata = array(); |
| | | $deletedata = array(); |
| | | foreach ($save_cols as $col => $val) { |
| | | $fld = $this->_map_field($col); |
| | | foreach ($this->fieldmap as $col => $fld) { |
| | | $val = $save_cols[$col]; |
| | | if ($fld) { |
| | | // The field does exist compare it to the ldap record. |
| | | if ($record[$col] != $val) { |
| | |
| | | $this->_debug("C: Delete [dn: $dn]: ".print_r($deletedata, true)); |
| | | if (!ldap_mod_del($this->conn, $dn, $deletedata)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | $this->_debug("S: OK"); |
| | |
| | | $this->_debug("C: Add [dn: $dn]: ".print_r($newdata, true)); |
| | | if (!ldap_mod_add($this->conn, $dn, $newdata)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } |
| | | $this->_debug("S: OK"); |
| | |
| | | $res = ldap_delete($this->conn, $dn); |
| | | if ($res === FALSE) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | $this->set_error(self::ERROR_SAVING, 'errorsaving'); |
| | | return false; |
| | | } // end if |
| | | $this->_debug("S: OK"); |
| | |
| | | */ |
| | | private function _ldap2result($rec) |
| | | { |
| | | global $RCMAIL; |
| | | |
| | | $out = array(); |
| | | |
| | | if ($rec['dn']) |
| | |
| | | |
| | | foreach ($this->fieldmap as $rf => $lf) |
| | | { |
| | | if ($rec[$lf]['count']) { |
| | | if ($rf == 'email' && $this->mail_domain && !strpos($rec[$lf][0], '@')) |
| | | $out[$rf] = sprintf('%s@%s', $rec[$lf][0], $this->mail_domain); |
| | | for ($i=0; $i < $rec[$lf]['count']; $i++) { |
| | | if (!($value = $rec[$lf][$i])) |
| | | continue; |
| | | if ($rf == 'email' && $this->mail_domain && !strpos($value, '@')) |
| | | $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain); |
| | | else if (in_array($rf, array('street','zipcode','locality','country','region'))) |
| | | $out['address'][$i][$rf] = $value; |
| | | else if ($rec[$lf]['count'] > 1) |
| | | $out[$rf][] = $value; |
| | | else |
| | | $out[$rf] = $rec[$lf][0]; |
| | | $out[$rf] = $value; |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | function quote_string($str, $dn=false) |
| | | { |
| | | // take firt entry if array given |
| | | if (is_array($str)) |
| | | $str = reset($str); |
| | | |
| | | if ($dn) |
| | | $replace = array(','=>'\2c', '='=>'\3d', '+'=>'\2b', '<'=>'\3c', |
| | | '>'=>'\3e', ';'=>'\3b', '\\'=>'\5c', '"'=>'\22', '#'=>'\23'); |
| | |
| | | */ |
| | | abstract function init(); |
| | | |
| | | |
| | | /** |
| | | * Attempt to load the given plugin which is required for the current plugin |
| | | * |
| | | * @param string Plugin name |
| | | * @return boolean True on success, false on failure |
| | | */ |
| | | public function require_plugin($plugin_name) |
| | | { |
| | | return $this->api->load_plugin($plugin_name); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Load local config file from plugins directory. |
| | | * The loaded values are patched over the global configuration. |
| | |
| | | $this->output = $rcmail->output; |
| | | $this->config = $rcmail->config; |
| | | |
| | | $plugins_dir = dir($this->dir); |
| | | $plugins_dir = unslashify($plugins_dir->path); |
| | | $plugins_enabled = (array)$rcmail->config->get('plugins', array()); |
| | | |
| | | foreach ($plugins_enabled as $plugin_name) { |
| | | $fn = $plugins_dir . 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... |
| | | if (is_subclass_of($plugin, 'rcube_plugin')) { |
| | | // ... task, request type and framed mode |
| | | if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $rcmail->task)) |
| | | && (!$plugin->noajax || is_a($this->output, 'rcube_template')) |
| | | && (!$plugin->noframe || empty($_REQUEST['_framed'])) |
| | | ) { |
| | | $plugin->init(); |
| | | $this->plugins[] = $plugin; |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | raise_error(array('code' => 520, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "No plugin class $plugin_name found in $fn"), true, false); |
| | | } |
| | | } |
| | | else { |
| | | raise_error(array('code' => 520, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Failed to load plugin file $fn"), true, false); |
| | | } |
| | | $this->load_plugin($plugin_name); |
| | | } |
| | | |
| | | // check existance of all required core plugins |
| | |
| | | } |
| | | |
| | | // load required core plugin if no derivate was found |
| | | if (!$loaded) { |
| | | $fn = $plugins_dir . DIRECTORY_SEPARATOR . $plugin_name . DIRECTORY_SEPARATOR . $plugin_name . '.php'; |
| | | |
| | | if (file_exists($fn)) { |
| | | include_once($fn); |
| | | |
| | | if (class_exists($plugin_name, false)) { |
| | | $plugin = new $plugin_name($this); |
| | | // check inheritance |
| | | if (is_subclass_of($plugin, 'rcube_plugin')) { |
| | | if (!$plugin->task || preg_match('/('.$plugin->task.')/i', $rcmail->task)) { |
| | | $plugin->init(); |
| | | $this->plugins[] = $plugin; |
| | | } |
| | | $loaded = true; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if (!$loaded) |
| | | $loaded = $this->load_plugin($plugin_name); |
| | | |
| | | // trigger fatal error if still not loaded |
| | | if (!$loaded) { |
| | |
| | | |
| | | |
| | | /** |
| | | * Load the specified plugin |
| | | * |
| | | * @param string Plugin name |
| | | * @return boolean True on success, false if not loaded or failure |
| | | */ |
| | | public function load_plugin($plugin_name) |
| | | { |
| | | static $plugins_dir; |
| | | |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | if (!$plugins_dir) { |
| | | $dir = dir($this->dir); |
| | | $plugins_dir = unslashify($dir->path); |
| | | } |
| | | |
| | | // plugin already loaded |
| | | if ($this->plugins[$plugin_name] || class_exists($plugin_name, false)) |
| | | return true; |
| | | |
| | | $fn = $plugins_dir . 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... |
| | | if (is_subclass_of($plugin, 'rcube_plugin')) { |
| | | // ... task, request type and framed mode |
| | | if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $rcmail->task)) /* |
| | | && (!$plugin->noajax || is_a($rcmail->output, 'rcube_template')) |
| | | && (!$plugin->noframe || empty($_REQUEST['_framed']))*/ |
| | | ) { |
| | | $plugin->init(); |
| | | $this->plugins[$plugin_name] = $plugin; |
| | | } |
| | | return true; |
| | | } |
| | | } |
| | | else { |
| | | raise_error(array('code' => 520, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "No plugin class $plugin_name found in $fn"), true, false); |
| | | } |
| | | } |
| | | else { |
| | | raise_error(array('code' => 520, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Failed to load plugin file $fn"), true, false); |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Allows a plugin object to register a callback for a certain hook |
| | | * |
| | | * @param string $hook Hook name |
| | |
| | | return $mime_type; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Detect image type of the given binary data by checking magic numbers |
| | | * |
| | | * @param string Binary file content |
| | | * @return string Detected mime-type or jpeg as fallback |
| | | */ |
| | | function rc_image_content_type($data) |
| | | { |
| | | $type = 'jpeg'; |
| | | if (preg_match('/^\x89\x50\x4E\x47/', $data)) $type = 'png'; |
| | | else if (preg_match('/^\x47\x49\x46\x38/', $data)) $type = 'gif'; |
| | | else if (preg_match('/^\x00\x00\x01\x00/', $data)) $type = 'ico'; |
| | | // else if (preg_match('/^\xFF\xD8\xFF\xE0/', $data)) $type = 'jpeg'; |
| | | |
| | | return 'image/' . $type; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * A method to guess encoding of a string. |
| | | * |
| | |
| | | $attrib['action'] = './'; |
| | | |
| | | // we already have a <form> tag |
| | | if ($attrib['form']) |
| | | if ($attrib['form']) { |
| | | if ($this->framed || !empty($_REQUEST['_framed'])) |
| | | $hidden->add(array('name' => '_framed', 'value' => '1')); |
| | | return $hidden->show() . $content; |
| | | } |
| | | else |
| | | return $this->form_tag($attrib, $hidden->show() . $content); |
| | | } |
| | |
| | | | program/include/rcube_vcard.php | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2008-2009, The Roundcube Dev Team | |
| | | | Copyright (C) 2008-2011, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | 'FN' => array(), |
| | | 'N' => array(array('','','','','')), |
| | | ); |
| | | private $fieldmap = array( |
| | | 'phone' => 'TEL', |
| | | 'birthday' => 'BDAY', |
| | | 'website' => 'URL', |
| | | 'notes' => 'NOTE', |
| | | 'email' => 'EMAIL', |
| | | 'address' => 'ADR', |
| | | 'gender' => 'X-GENDER', |
| | | 'maidenname' => 'X-MAIDENNAME', |
| | | 'anniversary' => 'X-ANNIVERSARY', |
| | | 'assistant' => 'X-ASSISTANT', |
| | | 'manager' => 'X-MANAGER', |
| | | 'spouse' => 'X-SPOUSE', |
| | | ); |
| | | private $typemap = array('iPhone' => 'mobile', 'CELL' => 'mobile'); |
| | | private $phonetypemap = array('HOME1' => 'HOME', 'BUSINESS1' => 'WORK', 'BUSINESS2' => 'WORK2', 'WORKFAX' => 'BUSINESSFAX'); |
| | | private $addresstypemap = array('BUSINESS' => 'WORK'); |
| | | private $immap = array('X-JABBER' => 'jabber', 'X-ICQ' => 'icq', 'X-MSN' => 'msn', 'X-AIM' => 'aim', 'X-YAHOO' => 'yahoo', 'X-SKYPE' => 'skype', 'X-SKYPE-USERNAME' => 'skype'); |
| | | |
| | | public $business = false; |
| | | public $displayname; |
| | |
| | | |
| | | |
| | | /** |
| | | * Return vCard data as associative array to be unsed in Roundcube address books |
| | | * |
| | | * @return array Hash array with key-value pairs |
| | | */ |
| | | public function get_assoc() |
| | | { |
| | | $out = array('name' => $this->displayname); |
| | | $typemap = $this->typemap; |
| | | |
| | | // copy name fields to output array |
| | | foreach (array('firstname','surname','middlename','nickname','organization') as $col) |
| | | $out[$col] = $this->$col; |
| | | |
| | | $out['prefix'] = $this->raw['N'][0][3]; |
| | | $out['suffix'] = $this->raw['N'][0][4]; |
| | | |
| | | // convert from raw vcard data into associative data for Roundcube |
| | | foreach (array_flip($this->fieldmap) as $tag => $col) { |
| | | foreach ((array)$this->raw[$tag] as $i => $raw) { |
| | | if (is_array($raw)) { |
| | | $k = -1; |
| | | $key = $col; |
| | | $subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]); |
| | | while ($k < count($raw['type']) && ($subtype == 'internet' || $subtype == 'pref')) |
| | | $subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]); |
| | | if ($subtype) |
| | | $key .= ':' . $subtype; |
| | | |
| | | // split ADR values into assoc array |
| | | if ($tag == 'ADR') { |
| | | list(,, $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']) = $raw; |
| | | $out[$key][] = $value; |
| | | } |
| | | else |
| | | $out[$key][] = $raw[0]; |
| | | } |
| | | else { |
| | | $out[$col][] = $raw; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // handle special IM fields as used by Apple |
| | | foreach ($this->immap as $tag => $type) { |
| | | foreach ((array)$this->raw[$tag] as $i => $raw) { |
| | | $out['im:'.$type][] = $raw[0]; |
| | | } |
| | | } |
| | | |
| | | // copy photo data |
| | | if ($this->raw['PHOTO']) |
| | | $out['photo'] = $this->raw['PHOTO'][0][0]; |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Convert the data structure into a vcard 3.0 string |
| | | */ |
| | | public function export() |
| | |
| | | |
| | | |
| | | /** |
| | | * Clear the given fields in the loaded vcard data |
| | | * |
| | | * @param array List of field names to be reset |
| | | */ |
| | | public function reset($fields = null) |
| | | { |
| | | if (!$fields) |
| | | $fields = array_merge(array_values($this->fieldmap), array_keys($this->immap), array('FN','N','ORG','NICKNAME','EMAIL','ADR','BDAY')); |
| | | |
| | | foreach ($fields as $f) |
| | | unset($this->raw[$f]); |
| | | |
| | | if (!$this->raw['N']) |
| | | $this->raw['N'] = array(array('','','','','')); |
| | | if (!$this->raw['FN']) |
| | | $this->raw['FN'] = array(); |
| | | |
| | | $this->email = array(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Setter for address record fields |
| | | * |
| | | * @param string Field name |
| | | * @param string Field value |
| | | * @param string Section name |
| | | * @param string Type/section name |
| | | */ |
| | | public function set($field, $value, $section = 'HOME') |
| | | public function set($field, $value, $type = 'HOME') |
| | | { |
| | | $field = strtolower($field); |
| | | $type = strtoupper($type); |
| | | $typemap = array_flip($this->typemap); |
| | | |
| | | switch ($field) { |
| | | case 'name': |
| | | case 'displayname': |
| | | $this->raw['FN'][0][0] = $value; |
| | | break; |
| | | |
| | | case 'surname': |
| | | $this->raw['N'][0][0] = $value; |
| | | break; |
| | | |
| | | case 'firstname': |
| | | $this->raw['N'][0][1] = $value; |
| | | break; |
| | | |
| | | case 'surname': |
| | | $this->raw['N'][0][0] = $value; |
| | | case 'middlename': |
| | | $this->raw['N'][0][2] = $value; |
| | | break; |
| | | |
| | | case 'prefix': |
| | | $this->raw['N'][0][3] = $value; |
| | | break; |
| | | |
| | | case 'suffix': |
| | | $this->raw['N'][0][4] = $value; |
| | | break; |
| | | |
| | | case 'nickname': |
| | |
| | | $this->raw['ORG'][0][0] = $value; |
| | | break; |
| | | |
| | | case 'photo': |
| | | $encoded = !preg_match('![^a-z0-9/=+-]!i', $value); |
| | | $this->raw['PHOTO'][0] = array(0 => $encoded ? $value : base64_encode($value), 'BASE64' => true); |
| | | break; |
| | | |
| | | case 'email': |
| | | $index = $this->get_type_index('EMAIL', $section); |
| | | if (!is_array($this->raw['EMAIL'][$index])) { |
| | | $this->raw['EMAIL'][$index] = array(0 => $value, 'type' => array('INTERNET', $section, 'pref')); |
| | | } |
| | | else { |
| | | $this->raw['EMAIL'][$index][0] = $value; |
| | | $this->raw['EMAIL'][] = array(0 => $value, 'type' => array_filter(array('INTERNET', $type))); |
| | | $this->email[] = $value; |
| | | break; |
| | | |
| | | case 'im': |
| | | // save IM subtypes into extension fields |
| | | $typemap = array_flip($this->immap); |
| | | if ($field = $typemap[strtolower($type)]) |
| | | $this->raw[$field][] = array(0 => $value); |
| | | break; |
| | | |
| | | case 'birthday': |
| | | if ($val = @strtotime($value)) |
| | | $this->raw['BDAY'][] = array(0 => date('Y-m-d', $val), 'value' => array('date')); |
| | | break; |
| | | |
| | | case 'address': |
| | | if ($this->addresstypemap[$type]) |
| | | $type = $this->addresstypemap[$type]; |
| | | |
| | | $value = $value[0] ? $value : array('', '', $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']); |
| | | |
| | | // fall through if not empty |
| | | if (!strlen(join('', $value))) |
| | | break; |
| | | |
| | | default: |
| | | if ($field == 'phone' && $this->phonetypemap[$type]) |
| | | $type = $this->phonetypemap[$type]; |
| | | |
| | | if (($tag = $this->fieldmap[$field]) && (is_array($value) || strlen($value))) { |
| | | $index = count($this->raw[$tag]); |
| | | $this->raw[$tag][$index] = (array)$value; |
| | | if ($type) |
| | | $this->raw[$tag][$index]['type'] = array(($typemap[$type] ? $typemap[$type] : $type)); |
| | | } |
| | | break; |
| | | } |
| | |
| | | |
| | | if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform) { |
| | | this.enable_command('save', true); |
| | | $("input[type='text']").first().select(); |
| | | this.enable_command('upload-photo', this.env.coltypes.photo ? true : false); |
| | | this.enable_command('delete-photo', this.env.coltypes.photo && this.env.action == 'edit'); |
| | | |
| | | for (var col in this.env.coltypes) |
| | | this.init_edit_field(col, null); |
| | | |
| | | $('.contactfieldgroup .row a.deletebutton').click(function(){ ref.delete_edit_field(this); return false }); |
| | | |
| | | $('select.addfieldmenu').change(function(e){ |
| | | ref.insert_edit_field($(this).val(), $(this).attr('rel'), this); |
| | | this.selectedIndex = 0; |
| | | }); |
| | | |
| | | $("input[type='text']").first().focus(); |
| | | } |
| | | else if (this.gui_objects.qsearchbox) { |
| | | this.enable_command('search', 'reset-search', 'moveto', true); |
| | |
| | | input_email.focus(); |
| | | break; |
| | | } |
| | | |
| | | // clear empty input fields |
| | | $('input.placeholder').each(function(){ if (this.value == this._placeholder) this.value = ''; }); |
| | | } |
| | | |
| | | this.gui_objects.editform.submit(); |
| | |
| | | |
| | | case 'export': |
| | | if (this.contact_list.rowcount > 0) { |
| | | var add_url = (this.env.source ? '_source='+urlencode(this.env.source)+'&' : ''); |
| | | if (this.env.search_request) |
| | | add_url += '_search='+this.env.search_request; |
| | | |
| | | this.goto_url('export', add_url); |
| | | this.goto_url('export', { _source:this.env.source, _gid:this.env.group, _search:this.env.search_request }); |
| | | } |
| | | break; |
| | | |
| | | case 'upload-photo': |
| | | this.upload_contact_photo(props); |
| | | break; |
| | | |
| | | case 'delete-photo': |
| | | this.replace_contact_photo('-del-'); |
| | | break; |
| | | |
| | | // user settings commands |
| | |
| | | |
| | | this.is_framed = function() |
| | | { |
| | | return (this.env.framed && parent.rcmail); |
| | | return (this.env.framed && parent.rcmail && parent.rcmail != this && parent.rcmail.command); |
| | | }; |
| | | |
| | | |
| | |
| | | |
| | | // create hidden iframe and post upload form |
| | | if (send) { |
| | | var ts = new Date().getTime(); |
| | | var frame_name = 'rcmupload'+ts; |
| | | |
| | | // have to do it this way for IE |
| | | // otherwise the form will be posted to a new window |
| | | if (document.all) { |
| | | var html = '<iframe name="'+frame_name+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>'; |
| | | document.body.insertAdjacentHTML('BeforeEnd',html); |
| | | } |
| | | else { // for standards-compilant browsers |
| | | var frame = document.createElement('iframe'); |
| | | frame.name = frame_name; |
| | | frame.style.border = 'none'; |
| | | frame.style.width = 0; |
| | | frame.style.height = 0; |
| | | frame.style.visibility = 'hidden'; |
| | | document.body.appendChild(frame); |
| | | } |
| | | |
| | | // handle upload errors, parsing iframe content in onload |
| | | $(frame_name).bind('load', {ts:ts}, function(e) { |
| | | this.async_upload_form(form, 'upload', function(e) { |
| | | var d, content = ''; |
| | | try { |
| | | if (this.contentDocument) { |
| | |
| | | if (bw.opera) |
| | | rcmail.env.uploadframe = e.data.ts; |
| | | }); |
| | | |
| | | form.target = frame_name; |
| | | form.action = this.env.comm_path+'&_action=upload&_uploadid='+ts; |
| | | form.setAttribute('enctype', 'multipart/form-data'); |
| | | form.submit(); |
| | | |
| | | // display upload indicator and cancel button |
| | | var content = this.get_label('uploading'); |
| | |
| | | }; |
| | | |
| | | |
| | | this.init_edit_field = function(col, elem) |
| | | { |
| | | if (!elem) |
| | | elem = $('.ff_' + col); |
| | | |
| | | elem.focus(function(){ ref.focus_textfield(this); }) |
| | | .blur(function(){ ref.blur_textfield(this); }) |
| | | .each(function(){ this._placeholder = ref.env.coltypes[col].label; ref.blur_textfield(this); }); |
| | | }; |
| | | |
| | | this.insert_edit_field = function(col, section, menu) |
| | | { |
| | | // just make pre-defined input field visible |
| | | var elem = $('#ff_'+col); |
| | | if (elem.length) { |
| | | elem.show().focus(); |
| | | $(menu).children('option[value="'+col+'"]').attr('disabled', true); |
| | | } |
| | | else { |
| | | var lastelem = $('.ff_'+col), |
| | | appendcontainer = $('#contactsection'+section+' .contactcontroller'+col); |
| | | |
| | | if (!appendcontainer.length) |
| | | appendcontainer = $('<fieldset>').addClass('contactfieldgroup contactcontroller'+col).insertAfter($('#contactsection'+section+' .contactfieldgroup').last()); |
| | | |
| | | if (appendcontainer.length && appendcontainer.get(0).nodeName == 'FIELDSET') { |
| | | var input, colprop = this.env.coltypes[col], |
| | | row = $('<div>').addClass('row'), |
| | | cell = $('<div>').addClass('contactfieldcontent data'), |
| | | label = $('<div>').addClass('contactfieldlabel label'); |
| | | |
| | | if (colprop.subtypes_select) |
| | | label.html(colprop.subtypes_select); |
| | | else |
| | | label.html(colprop.label); |
| | | |
| | | var name_suffix = colprop.limit != 1 ? '[]' : ''; |
| | | if (colprop.type == 'text' || colprop.type == 'date') { |
| | | input = $('<input>') |
| | | .addClass('ff_'+col) |
| | | .attr('type', 'text') |
| | | .attr('name', '_'+col+name_suffix) |
| | | .attr('size', colprop.size) |
| | | .appendTo(cell); |
| | | |
| | | this.init_edit_field(col, input); |
| | | } |
| | | else if (colprop.type == 'composite') { |
| | | var childcol, cp, first; |
| | | for (var childcol in colprop.childs) { |
| | | cp = colprop.childs[childcol]; |
| | | input = $('<input>') |
| | | .addClass('ff_'+childcol) |
| | | .attr('type', 'text') |
| | | .attr('name', '_'+childcol+name_suffix) |
| | | .attr('size', cp.size) |
| | | .appendTo(cell); |
| | | cell.append(" "); |
| | | this.init_edit_field(childcol, input); |
| | | if (!first) first = input; |
| | | } |
| | | input = first; // set focus to the first of this composite fields |
| | | } |
| | | else if (colprop.type == 'select') { |
| | | input = $('<select>') |
| | | .addClass('ff_'+col) |
| | | .attr('name', '_'+col+name_suffix) |
| | | .appendTo(cell); |
| | | |
| | | var options = input.attr('options'); |
| | | options[options.length] = new Option('---', ''); |
| | | if (colprop.options) |
| | | $.each(colprop.options, function(i, val){ options[options.length] = new Option(val, i); }); |
| | | } |
| | | |
| | | if (input) { |
| | | var delbutton = $('<a href="#del"></a>') |
| | | .addClass('contactfieldbutton deletebutton') |
| | | .attr('title', this.get_label('delete')) |
| | | .attr('rel', col) |
| | | .html(this.env.delbutton) |
| | | .click(function(){ ref.delete_edit_field(this); return false }) |
| | | .appendTo(cell); |
| | | |
| | | row.append(label).append(cell).appendTo(appendcontainer.show()); |
| | | input.first().focus(); |
| | | |
| | | // disable option if limit reached |
| | | if (!colprop.count) colprop.count = 0; |
| | | if (++colprop.count == colprop.limit && colprop.limit) |
| | | $(menu).children('option[value="'+col+'"]').attr('disabled', true); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | this.delete_edit_field = function(elem) |
| | | { |
| | | var col = $(elem).attr('rel'), |
| | | colprop = this.env.coltypes[col], |
| | | fieldset = $(elem).parents('fieldset.contactfieldgroup'), |
| | | addmenu = fieldset.parent().find('select.addfieldmenu'); |
| | | |
| | | // just clear input but don't hide the last field |
| | | if (--colprop.count <= 0 && colprop.visible) |
| | | $(elem).parent().children('input').val('').blur(); |
| | | else { |
| | | $(elem).parents('div.row').remove(); |
| | | // hide entire fieldset if no more rows |
| | | if (!fieldset.children('div.row').length) |
| | | fieldset.hide(); |
| | | } |
| | | |
| | | // enable option in add-field selector or insert it if necessary |
| | | if (addmenu.length) { |
| | | var option = addmenu.children('option[value="'+col+'"]'); |
| | | if (option.length) |
| | | option.attr('disabled', false); |
| | | else |
| | | option = $('<option>').attr('value', col).html(colprop.label).appendTo(addmenu); |
| | | addmenu.show(); |
| | | } |
| | | }; |
| | | |
| | | |
| | | this.upload_contact_photo = function(form) |
| | | { |
| | | if (form && form.elements._photo.value) { |
| | | this.async_upload_form(form, 'upload-photo', function(e) { |
| | | rcmail.set_busy(false, null, rcmail.photo_upload_id); |
| | | }); |
| | | |
| | | // display upload indicator |
| | | this.photo_upload_id = this.set_busy(true, 'uploading'); |
| | | } |
| | | }; |
| | | |
| | | this.replace_contact_photo = function(id) |
| | | { |
| | | $('#ff_photo').val(id); |
| | | |
| | | var buttons = this.buttons['upload-photo']; |
| | | for (var n=0; n < buttons.length; n++) |
| | | $('#'+buttons[n].id).html(this.get_label(id == '-del-' ? 'addphoto' : 'replacephoto')); |
| | | |
| | | var img_src = id == '-del-' ? this.env.photo_placeholder : |
| | | this.env.comm_path + '&_action=photo&_source=' + this.env.source + '&_cid=' + this.env.cid + '&_photo=' + id; |
| | | $(this.gui_objects.contactphoto).children('img').attr('src', img_src); |
| | | |
| | | this.enable_command('delete-photo', id != '-del-'); |
| | | }; |
| | | |
| | | this.photo_upload_end = function() |
| | | { |
| | | this.set_busy(false, null, this.photo_upload_id); |
| | | delete this.photo_upload_id; |
| | | }; |
| | | |
| | | |
| | | /*********************************************************/ |
| | | /********* user settings methods *********/ |
| | | /*********************************************************/ |
| | |
| | | } |
| | | }; |
| | | |
| | | |
| | | this.focus_textfield = function(elem) |
| | | { |
| | | elem._hasfocus = true; |
| | | var $elem = $(elem); |
| | | if ($elem.hasClass('placeholder') || $elem.val() == elem._placeholder) |
| | | $elem.val('').removeClass('placeholder').attr('spellcheck', true); |
| | | }; |
| | | |
| | | this.blur_textfield = function(elem) |
| | | { |
| | | elem._hasfocus = false; |
| | | var $elem = $(elem); |
| | | if (elem._placeholder && (!$elem.val() || $elem.val() == elem._placeholder)) |
| | | $elem.addClass('placeholder').attr('spellcheck', false).val(elem._placeholder); |
| | | }; |
| | | |
| | | // write to the document/window title |
| | | this.set_pagetitle = function(title) |
| | | { |
| | |
| | | /********* remote request methods *********/ |
| | | /********************************************************/ |
| | | |
| | | // compose a valid url with the given parameters |
| | | this.url = function(action, query) |
| | | { |
| | | var querystring = typeof(query) == 'string' ? '&' + query : ''; |
| | | |
| | | if (typeof action != 'string') |
| | | query = action; |
| | | else if (!query || typeof(query) != 'object') |
| | | query = {}; |
| | | |
| | | if (action) |
| | | query._action = action; |
| | | else |
| | | query._action = this.env.action; |
| | | |
| | | var base = this.env.comm_path; |
| | | |
| | | // overwrite task name |
| | | if (query._action.match(/([a-z]+)\/([a-z-_]+)/)) { |
| | | query._action = RegExp.$2; |
| | | base = base.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); |
| | | } |
| | | |
| | | // remove undefined values |
| | | var param = {}; |
| | | for (var k in query) { |
| | | if (typeof(query[k]) != 'undefined' && query[k] !== null) |
| | | param[k] = query[k]; |
| | | } |
| | | |
| | | return base + '&' + $.param(param) + querystring; |
| | | }; |
| | | |
| | | this.redirect = function(url, lock) |
| | | { |
| | | if (lock || lock === null) |
| | |
| | | |
| | | this.goto_url = function(action, query, lock) |
| | | { |
| | | var url = this.env.comm_path, |
| | | querystring = query ? '&'+query : ''; |
| | | |
| | | // overwrite task name |
| | | if (action.match(/([a-z]+)\/([a-z-_]+)/)) { |
| | | action = RegExp.$2; |
| | | url = url.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); |
| | | } |
| | | |
| | | this.redirect(url+'&_action='+action+querystring, lock); |
| | | this.redirect(this.url(action, query)); |
| | | }; |
| | | |
| | | // send a http request to the server |
| | | this.http_request = function(action, query, lock) |
| | | { |
| | | var url = this.env.comm_path; |
| | | |
| | | // overwrite task name |
| | | if (action.match(/([a-z]+)\/([a-z-_]+)/)) { |
| | | action = RegExp.$2; |
| | | url = url.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); |
| | | } |
| | | var url = this.url(action, query); |
| | | |
| | | // trigger plugin hook |
| | | var result = this.triggerEvent('request'+action, query); |
| | |
| | | query = result; |
| | | } |
| | | |
| | | url += '&_remote=1&_action=' + action + (query ? '&' : '') + query; |
| | | url += '&_remote=1'; |
| | | |
| | | // send request |
| | | console.log('HTTP GET: ' + url); |
| | |
| | | // send a http POST request to the server |
| | | this.http_post = function(action, postdata, lock) |
| | | { |
| | | var url = this.env.comm_path; |
| | | |
| | | // overwrite task name |
| | | if (action.match(/([a-z]+)\/([a-z-_]+)/)) { |
| | | action = RegExp.$2; |
| | | url = url.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); |
| | | } |
| | | |
| | | url += '&_action=' + action; |
| | | var url = this.url(action); |
| | | |
| | | if (postdata && typeof(postdata) == 'object') { |
| | | postdata._remote = 1; |
| | |
| | | this.display_message(this.get_label('servererror') + ' (' + errmsg + ')', 'error'); |
| | | }; |
| | | |
| | | // post the given form to a hidden iframe |
| | | this.async_upload_form = function(form, action, onload) |
| | | { |
| | | var ts = new Date().getTime(); |
| | | var frame_name = 'rcmupload'+ts; |
| | | |
| | | // have to do it this way for IE |
| | | // otherwise the form will be posted to a new window |
| | | if (document.all) { |
| | | var html = '<iframe name="'+frame_name+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>'; |
| | | document.body.insertAdjacentHTML('BeforeEnd', html); |
| | | } |
| | | else { // for standards-compilant browsers |
| | | var frame = document.createElement('iframe'); |
| | | frame.name = frame_name; |
| | | frame.style.border = 'none'; |
| | | frame.style.width = 0; |
| | | frame.style.height = 0; |
| | | frame.style.visibility = 'hidden'; |
| | | document.body.appendChild(frame); |
| | | } |
| | | |
| | | // handle upload errors, parsing iframe content in onload |
| | | $(frame_name).bind('load', {ts:ts}, onload); |
| | | |
| | | form.target = frame_name; |
| | | form.action = this.url(action, { _uploadid:ts }); |
| | | form.setAttribute('enctype', 'multipart/form-data'); |
| | | form.submit(); |
| | | }; |
| | | |
| | | // starts interval for keep-alive/check-recent signal |
| | | this.start_keepalive = function() |
| | | { |
| | |
| | | $labels['name'] = 'Display name'; |
| | | $labels['firstname'] = 'First name'; |
| | | $labels['surname'] = 'Last name'; |
| | | $labels['middlename'] = 'Middle name'; |
| | | $labels['nameprefix'] = 'Prefix'; |
| | | $labels['namesuffix'] = 'Suffix'; |
| | | $labels['nickname'] = 'Nickname'; |
| | | $labels['jobtitle'] = 'Job title'; |
| | | $labels['organization'] = 'Company'; |
| | | $labels['department'] = 'Department'; |
| | | $labels['gender'] = 'Gender'; |
| | | $labels['maidenname'] = 'Maiden name'; |
| | | $labels['email'] = 'E-Mail'; |
| | | $labels['phone'] = 'Phone'; |
| | | $labels['address'] = 'Address'; |
| | | $labels['street'] = 'Street'; |
| | | $labels['locality'] = 'City'; |
| | | $labels['zipcode'] = 'Zip code'; |
| | | $labels['region'] = 'Region'; |
| | | $labels['country'] = 'Country'; |
| | | $labels['birthday'] = 'Birthday'; |
| | | $labels['anniversary'] = 'Anniversary'; |
| | | $labels['website'] = 'Website'; |
| | | $labels['instantmessenger'] = 'IM'; |
| | | $labels['notes'] = 'Notes'; |
| | | $labels['male'] = 'male'; |
| | | $labels['female'] = 'female'; |
| | | $labels['manager'] = 'Manager'; |
| | | $labels['assistant'] = 'Assistant'; |
| | | $labels['spouse'] = 'Spouse'; |
| | | |
| | | $labels['addfield'] = 'Add field...'; |
| | | $labels['addcontact'] = 'Add new contact'; |
| | | $labels['editcontact'] = 'Edit contact'; |
| | | $labels['contacts'] = 'Contacts'; |
| | |
| | | $labels['save'] = 'Save'; |
| | | $labels['delete'] = 'Delete'; |
| | | $labels['rename'] = 'Rename'; |
| | | $labels['addphoto'] = 'Add'; |
| | | $labels['replacephoto'] = 'Replace'; |
| | | |
| | | $labels['newcontact'] = 'Create new contact card'; |
| | | $labels['deletecontact'] = 'Delete selected contacts'; |
| | |
| | | $messages['selectimportfile'] = 'Please select a file to upload'; |
| | | $messages['addresswriterror'] = 'The selected address book is not writeable'; |
| | | $messages['contactaddedtogroup'] = 'Successfully added the contacts to this group'; |
| | | $messages['contactremovedfromgroup'] = 'Successfully remove contacts from this group'; |
| | | $messages['contactremovedfromgroup'] = 'Successfully removed contacts from this group'; |
| | | $messages['importwait'] = 'Importing, please wait...'; |
| | | $messages['importerror'] = 'Import failed! The uploaded file is not a valid vCard file.'; |
| | | $messages['importconfirm'] = '<b>Successfully imported $inserted contacts, $skipped existing entries skipped</b>:<p><em>$names</em></p>'; |
| | |
| | | $messages['nametoolong'] = 'Name is too long'; |
| | | $messages['folderupdated'] = 'Folder updated successfully'; |
| | | $messages['foldercreated'] = 'Folder created successfully'; |
| | | $messages['invalidimageformat'] = 'Not a valid image format'; |
| | | |
| | | ?> |
| | |
| | | 'record' => $a_record, 'source' => $target, 'group' => $target_group)); |
| | | |
| | | if (!$plugin['abort']) { |
| | | if ($insert_id = $TARGET->insert($a_record, false)) { |
| | | if ($insert_id = $TARGET->insert($plugin['record'], false)) { |
| | | $ids[] = $insert_id; |
| | | $success++; |
| | | } |
| | |
| | | // count contacts for this user |
| | | $result = $CONTACTS->count(); |
| | | |
| | | // update saved search after data changed |
| | | if (($search_request = $_REQUEST['_search']) && isset($_SESSION['search'][$search_request])) |
| | | $_SESSION['search'][$search_request] = $CONTACTS->refresh_search(); |
| | | |
| | | // update message count display |
| | | $OUTPUT->set_env('pagecount', ceil($result->count / $CONTACTS->page_size)); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text($result->count)); |
| | |
| | | } |
| | | |
| | | |
| | | function rcmail_contact_editform($attrib) |
| | | function rcmail_contact_edithead($attrib) |
| | | { |
| | | global $RCMAIL, $CONTACTS, $OUTPUT; |
| | | global $RCMAIL, $CONTACTS; |
| | | |
| | | // check if we have a valid result |
| | | if ($RCMAIL->action != 'add' |
| | | && !(($result = $CONTACTS->get_result()) && ($record = $result->first())) |
| | | ) { |
| | | $OUTPUT->show_message('contactnotfound'); |
| | | $RCMAIL->output->show_message('contactnotfound'); |
| | | return false; |
| | | } |
| | | |
| | | $i_size = !empty($attrib['size']) ? $attrib['size'] : 20; |
| | | |
| | | $form = array( |
| | | 'head' => array( |
| | | 'content' => array( |
| | | 'prefix' => array('size' => $i_size), |
| | | 'firstname' => array('size' => $i_size, 'visible' => true), |
| | | 'middlename' => array('size' => $i_size), |
| | | 'surname' => array('size' => $i_size, 'visible' => true), |
| | | 'suffix' => array('size' => $i_size), |
| | | 'name' => array('size' => 2*$i_size), |
| | | 'nickname' => array('size' => 2*$i_size), |
| | | 'company' => array('size' => $i_size), |
| | | 'department' => array('size' => $i_size), |
| | | 'jobtitle' => array('size' => $i_size), |
| | | ) |
| | | ) |
| | | ); |
| | | |
| | | list($form_start, $form_end) = get_form_tags($attrib); |
| | | unset($attrib['form'], $attrib['name'], $attrib['size']); |
| | | |
| | | // return the address edit form |
| | | $out = rcmail_contact_form($form, $record, $attrib); |
| | | |
| | | return $form_start . $out . $form_end; |
| | | } |
| | | |
| | | |
| | | function rcmail_contact_editform($attrib) |
| | | { |
| | | global $RCMAIL, $CONTACTS, $CONTACT_COLTYPES; |
| | | |
| | | // check if we have a valid result |
| | | if ($RCMAIL->action != 'add' |
| | | && !(($result = $CONTACTS->get_result()) && ($record = $result->first())) |
| | | ) { |
| | | $RCMAIL->output->show_message('contactnotfound'); |
| | | return false; |
| | | } |
| | | |
| | | // add some labels to client |
| | | $OUTPUT->add_label('noemailwarning', 'nonamewarning'); |
| | | $RCMAIL->output->add_label('noemailwarning', 'nonamewarning'); |
| | | |
| | | $i_size = !empty($attrib['size']) ? $attrib['size'] : 40; |
| | | $t_rows = !empty($attrib['textarearows']) ? $attrib['textarearows'] : 6; |
| | | $t_rows = !empty($attrib['textarearows']) ? $attrib['textarearows'] : 10; |
| | | $t_cols = !empty($attrib['textareacols']) ? $attrib['textareacols'] : 40; |
| | | |
| | | $form = array( |
| | | 'info' => array( |
| | | 'name' => rcube_label('contactproperties'), |
| | | 'content' => array( |
| | | 'name' => array('type' => 'text', 'size' => $i_size), |
| | | 'firstname' => array('type' => 'text', 'size' => $i_size), |
| | | 'surname' => array('type' => 'text', 'size' => $i_size), |
| | | 'email' => array('type' => 'text', 'size' => $i_size), |
| | | 'gender' => array('visible' => false), |
| | | 'maidenname' => array('size' => $i_size), |
| | | 'email' => array('size' => $i_size, 'visible' => true), |
| | | 'phone' => array('size' => $i_size, 'visible' => true), |
| | | 'address' => array('visible' => true), |
| | | 'birthday' => array('size' => 12), |
| | | 'anniversary' => array('size' => $i_size), |
| | | 'website' => array('size' => $i_size), |
| | | 'im' => array('size' => $i_size), |
| | | 'manager' => array('size' => $i_size), |
| | | 'assistant' => array('size' => $i_size), |
| | | 'spouse' => array('size' => $i_size), |
| | | ), |
| | | ), |
| | | ); |
| | | |
| | | if (isset($CONTACT_COLTYPES['notes'])) { |
| | | $form['notes'] = array( |
| | | 'name' => rcube_label('notes'), |
| | | 'content' => array( |
| | | 'notes' => array('size' => $t_cols, 'rows' => $t_rows, 'label' => false, 'visible' => true, 'limit' => 1), |
| | | ), |
| | | 'single' => true, |
| | | ); |
| | | } |
| | | |
| | | list($form_start, $form_end) = get_form_tags($attrib); |
| | | unset($attrib['form']); |
| | | |
| | | // return the complete address edit form as table |
| | | $out = rcmail_contact_form($form, $record); |
| | | $out = rcmail_contact_form($form, $record, $attrib); |
| | | |
| | | return $form_start . $out . $form_end; |
| | | } |
| | | |
| | | |
| | | function rcmail_upload_photo_form($attrib) |
| | | { |
| | | global $OUTPUT; |
| | | |
| | | // add ID if not given |
| | | if (!$attrib['id']) |
| | | $attrib['id'] = 'rcmUploadbox'; |
| | | |
| | | // find max filesize value |
| | | $max_filesize = parse_bytes(ini_get('upload_max_filesize')); |
| | | $max_postsize = parse_bytes(ini_get('post_max_size')); |
| | | if ($max_postsize && $max_postsize < $max_filesize) |
| | | $max_filesize = $max_postsize; |
| | | $max_filesize = show_bytes($max_filesize); |
| | | |
| | | $hidden = new html_hiddenfield(array('name' => '_cid', 'value' => $GLOBALS['cid'])); |
| | | $input = new html_inputfield(array('type' => 'file', 'name' => '_photo', 'size' => $attrib['size'])); |
| | | $button = new html_inputfield(array('type' => 'button')); |
| | | |
| | | $out = html::div($attrib, |
| | | $OUTPUT->form_tag(array('name' => 'uploadform', 'method' => 'post', 'enctype' => 'multipart/form-data'), |
| | | $hidden->show() . |
| | | html::div(null, $input->show()) . |
| | | html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . |
| | | html::div('buttons', |
| | | $button->show(rcube_label('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . |
| | | $button->show(rcube_label('upload'), array('class' => 'button mainaction', 'onclick' => JS_OBJECT_NAME . ".command('upload-photo', this.form)")) |
| | | ) |
| | | ) |
| | | ); |
| | | |
| | | $OUTPUT->add_label('addphoto','replacephoto'); |
| | | $OUTPUT->add_gui_object('uploadbox', $attrib['id']); |
| | | return $out; |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | $OUTPUT->add_handler('contactedithead', 'rcmail_contact_edithead'); |
| | | $OUTPUT->add_handler('contacteditform', 'rcmail_contact_editform'); |
| | | $OUTPUT->add_handler('contactphoto', 'rcmail_contact_photo'); |
| | | $OUTPUT->add_handler('photouploadform', 'rcmail_upload_photo_form'); |
| | | |
| | | if (!$CONTACTS->get_result() && $OUTPUT->template_exists('contactadd')) |
| | | $OUTPUT->send('contactadd'); |
| | |
| | | header('Content-Disposition: attachment; filename="rcube_contacts.vcf"'); |
| | | |
| | | while ($result && ($row = $result->next())) { |
| | | // we already have a vcard record |
| | | if ($row['vcard']) { |
| | | echo $row['vcard']; |
| | | } |
| | | // copy values into vcard object |
| | | else { |
| | | $vcard = new rcube_vcard($row['vcard']); |
| | | $vcard->set('displayname', $row['name']); |
| | | $vcard->set('firstname', $row['firstname']); |
| | | $vcard->set('surname', $row['surname']); |
| | | $vcard->set('email', $row['email']); |
| | | $vcard->reset(); |
| | | foreach ($row as $key => $values) { |
| | | list($field, $section) = explode(':', $key); |
| | | foreach ((array)$values as $value) { |
| | | if (is_array($value) || strlen($value)) |
| | | $vcard->set($field, $value, strtoupper($section)); |
| | | } |
| | | } |
| | | |
| | | echo $vcard->export(); |
| | | } |
| | | } |
| | | |
| | | exit; |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | // general definition of contact coltypes |
| | | $CONTACT_COLTYPES = array( |
| | | 'name' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('name')), |
| | | 'firstname' => array('type' => 'text', 'size' => 19, 'limit' => 1, 'label' => rcube_label('firstname')), |
| | | 'surname' => array('type' => 'text', 'size' => 19, 'limit' => 1, 'label' => rcube_label('surname')), |
| | | 'middlename' => array('type' => 'text', 'size' => 19, 'limit' => 1, 'label' => rcube_label('middlename')), |
| | | 'prefix' => array('type' => 'text', 'size' => 8, 'limit' => 1, 'label' => rcube_label('nameprefix')), |
| | | 'suffix' => array('type' => 'text', 'size' => 8, 'limit' => 1, 'label' => rcube_label('namesuffix')), |
| | | 'nickname' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('nickname')), |
| | | 'jobtitle' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('jobtitle')), |
| | | 'organization' => array('type' => 'text', 'size' => 19, 'limit' => 1, 'label' => rcube_label('organization')), |
| | | 'department' => array('type' => 'text', 'size' => 19, 'limit' => 1, 'label' => rcube_label('department')), |
| | | 'gender' => array('type' => 'select', 'limit' => 1, 'label' => rcube_label('gender'), 'options' => array('male' => rcube_label('male'), 'female' => rcube_label('female'))), |
| | | 'maidenname' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('maidenname')), |
| | | 'email' => array('type' => 'text', 'size' => 40, 'label' => rcube_label('email'), 'subtypes' => array('home','work','other')), |
| | | 'phone' => array('type' => 'text', 'size' => 40, 'label' => rcube_label('phone'), 'subtypes' => array('home','home2','work','work2','mobile','main','homefax','workfax','car','pager','video','assistant','other')), |
| | | 'address' => array('type' => 'composite', 'label' => rcube_label('address'), 'subtypes' => array('home','work','other'), 'childs' => array( |
| | | 'street' => array('type' => 'text', 'size' => 40, 'label' => rcube_label('street')), |
| | | 'locality' => array('type' => 'text', 'size' => 28, 'label' => rcube_label('locality')), |
| | | 'zipcode' => array('type' => 'text', 'size' => 8, 'label' => rcube_label('zipcode')), |
| | | 'region' => array('type' => 'text', 'size' => 12, 'label' => rcube_label('region')), |
| | | 'country' => array('type' => 'text', 'size' => 40, 'label' => rcube_label('country')), |
| | | )), |
| | | 'birthday' => array('type' => 'date', 'size' => 12, 'label' => rcube_label('birthday'), 'limit' => 1, 'render_func' => 'rcmail_format_date_col'), |
| | | 'anniversary' => array('type' => 'date', 'size' => 12, 'label' => rcube_label('anniversary'), 'limit' => 1, 'render_func' => 'rcmail_format_date_col'), |
| | | 'website' => array('type' => 'text', 'size' => 40, 'label' => rcube_label('website'), 'subtypes' => array('homepage','work','blog','other')), |
| | | 'im' => array('type' => 'text', 'size' => 40, 'label' => rcube_label('instantmessenger'), 'subtypes' => array('aim','icq','msn','yahoo','jabber','skype','other')), |
| | | 'notes' => array('type' => 'textarea', 'size' => 40, 'rows' => 15, 'label' => rcube_label('notes'), 'limit' => 1), |
| | | 'photo' => array('type' => 'image', 'limit' => 1), |
| | | 'assistant' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('assistant')), |
| | | 'manager' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('manager')), |
| | | 'spouse' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('spouse')), |
| | | // TODO: define fields for vcards like GEO, KEY |
| | | ); |
| | | |
| | | // reduce/extend $CONTACT_COLTYPES with specification from the current $CONTACT object |
| | | if (is_array($CONTACTS->coltypes)) { |
| | | // remove cols not listed by the backend class |
| | | $contact_cols = $CONTACTS->coltypes[0] ? array_flip($CONTACTS->coltypes) : $CONTACTS->coltypes; |
| | | $CONTACT_COLTYPES = array_intersect_key($CONTACT_COLTYPES, $contact_cols); |
| | | // add associative coltypes definition |
| | | if (!$CONTACTS->coltypes[0]) { |
| | | foreach ($CONTACTS->coltypes as $col => $colprop) |
| | | $CONTACT_COLTYPES[$col] = $CONTACT_COLTYPES[$col] ? array_merge($CONTACT_COLTYPES[$col], $colprop) : $colprop; |
| | | } |
| | | } |
| | | |
| | | $OUTPUT->set_env('photocol', is_array($CONTACT_COLTYPES['photo'])); |
| | | |
| | | |
| | | function rcmail_directory_list($attrib) |
| | | { |
| | | global $RCMAIL, $OUTPUT; |
| | |
| | | html::a(array('href' => '%s', |
| | | 'onclick' => "return ".JS_OBJECT_NAME.".command('list','%s',this)"), '%s')); |
| | | |
| | | if (!$current && strtolower($RCMAIL->config->get('address_book_type', 'sql')) != 'ldap') { |
| | | $current = '0'; |
| | | } |
| | | else if (!$current) { |
| | | // DB address book not used, see if a source is set, if not use the |
| | | // first LDAP directory. |
| | | $current = key((array)$RCMAIL->config->get('ldap_public', array())); |
| | | } |
| | | // currently selected is the first address source in the list |
| | | if (!isset($current)) |
| | | $current = strval(key((array)$OUTPUT->env['address_sources'])); |
| | | |
| | | foreach ((array)$OUTPUT->env['address_sources'] as $j => $source) { |
| | | $id = $source['id'] ? $source['id'] : $j; |
| | | $id = strval($source['id'] ? $source['id'] : $j); |
| | | $js_id = JQ($id); |
| | | $dom_id = preg_replace('/[^a-z0-9\-_]/i', '', $id); |
| | | $out .= sprintf($line_templ, $dom_id, ($current == $id ? 'selected' : ''), |
| | | $dom_id = preg_replace('/[^a-z0-9\-_]/i', '_', $id); |
| | | $out .= sprintf($line_templ, $dom_id, ($current === $id ? 'selected' : ''), |
| | | Q(rcmail_url(null, array('_source' => $id))), |
| | | $js_id, (!empty($source['name']) ? Q($source['name']) : Q($id))); |
| | | $groupdata = rcmail_contact_groups(array('out' => $out, 'jsdata' => $jsdata, 'source' => $id)); |
| | | |
| | | $groupdata = array('out' => $out, 'jsdata' => $jsdata, 'source' => $id); |
| | | if ($source['groups']) |
| | | $groupdata = rcmail_contact_groups($groupdata); |
| | | $jsdata = $groupdata['jsdata']; |
| | | $out = $groupdata['out']; |
| | | } |
| | |
| | | { |
| | | global $CONTACTS, $OUTPUT; |
| | | |
| | | // define list of cols to be displayed |
| | | $a_show_cols = array('name'); |
| | | |
| | | // count contacts for this user |
| | | $result = $CONTACTS->list_records(); |
| | | $result = $CONTACTS->list_records($a_show_cols); |
| | | |
| | | // add id to message list table if not specified |
| | | if (!strlen($attrib['id'])) |
| | | $attrib['id'] = 'rcmAddressList'; |
| | | |
| | | // define list of cols to be displayed |
| | | $a_show_cols = array('name'); |
| | | |
| | | // create XHTML table |
| | | $out = rcube_table_output($attrib, $result->records, $a_show_cols, $CONTACTS->primary_key); |
| | |
| | | } |
| | | |
| | | |
| | | function rcmail_contact_form($form, $record) |
| | | function rcmail_contact_form($form, $record, $attrib = null) |
| | | { |
| | | global $RCMAIL; |
| | | global $RCMAIL, $CONFIG; |
| | | |
| | | // Allow plugins to modify contact form content |
| | | $plugin = $RCMAIL->plugins->exec_hook('contact_form', array( |
| | |
| | | |
| | | $form = $plugin['form']; |
| | | $record = $plugin['record']; |
| | | $edit_mode = $RCMAIL->action != 'show'; |
| | | $del_button = $attrib['deleteicon'] ? html::img(array('src' => $CONFIG['skin_path'] . $attrib['deleteicon'], 'alt' => rcube_label('delete'))) : rcube_label('delete'); |
| | | unset($attrib['deleteicon']); |
| | | $out = ''; |
| | | |
| | | foreach ($form as $fieldset) { |
| | | // get default coltypes |
| | | $coltypes = $GLOBALS['CONTACT_COLTYPES']; |
| | | $coltype_lables = array(); |
| | | |
| | | foreach ($coltypes as $col => $prop) { |
| | | if ($prop['subtypes']) { |
| | | $select_subtype = new html_select(array('name' => '_subtype_'.$col.'[]', 'class' => 'contactselectsubtype')); |
| | | $select_subtype->add($prop['subtypes']); |
| | | $coltypes[$col]['subtypes_select'] = $select_subtype->show(); |
| | | } |
| | | if ($prop['childs']) { |
| | | foreach ($prop['childs'] as $childcol => $cp) |
| | | $coltype_lables[$childcol] = array('label' => $cp['label']); |
| | | } |
| | | } |
| | | |
| | | foreach ($form as $section => $fieldset) { |
| | | // skip empty sections |
| | | if (empty($fieldset['content'])) |
| | | continue; |
| | | |
| | | $select_add = new html_select(array('class' => 'addfieldmenu', 'rel' => $section)); |
| | | $select_add->add(rcube_label('addfield'), ''); |
| | | |
| | | // render head section with name fields (not a regular list of rows) |
| | | if ($section == 'head') { |
| | | $content = ''; |
| | | if (is_array($fieldset['content'])) { |
| | | $table = new html_table(array('cols' => 2)); |
| | | |
| | | foreach ($fieldset['content'] as $col => $colprop) { |
| | | $colprop['id'] = 'rcmfd_'.$col; |
| | | $names_arr = array($record['prefix'], $record['firstname'], $record['middlename'], $record['surname'], $record['suffix']); |
| | | if ($record['name'] == join(' ', array_filter($names_arr))) |
| | | unset($record['name']); |
| | | |
| | | $label = !empty($colprop['label']) ? $colprop['label'] : rcube_label($col); |
| | | // group fields |
| | | $field_blocks = array( |
| | | 'names' => array('prefix','firstname','middlename','surname','suffix'), |
| | | 'displayname' => array('name'), |
| | | 'nickname' => array('nickname'), |
| | | 'jobnames' => array('organization','department','jobtitle'), |
| | | ); |
| | | foreach ($field_blocks as $blockname => $colnames) { |
| | | $fields = ''; |
| | | foreach ($colnames as $col) { |
| | | // skip cols unknown to the backend |
| | | if (!$coltypes[$col]) |
| | | continue; |
| | | |
| | | if (!empty($colprop['value'])) { |
| | | $value = $colprop['value']; |
| | | } |
| | | else if ($RCMAIL->action == 'show') { |
| | | $value = $record[$col]; |
| | | if ($RCMAIL->action == 'show') { |
| | | if (!empty($record[$col])) |
| | | $fields .= html::span('namefield ' . $col, Q($record[$col])) . " "; |
| | | } |
| | | else { |
| | | $value = rcmail_get_edit_field($col, $record[$col], $colprop, $colprop['type']); |
| | | $colprop = (array)$fieldset['content'][$col] + (array)$coltypes[$col]; |
| | | $colprop['id'] = 'ff_'.$col; |
| | | if (empty($record[$col]) && !$colprop['visible']) { |
| | | $colprop['style'] = 'display:none'; |
| | | $select_add->add($colprop['label'], $col); |
| | | } |
| | | $fields .= rcmail_get_edit_field($col, $record[$col], $colprop, $colprop['type']); |
| | | } |
| | | } |
| | | $content .= html::div($blockname, $fields); |
| | | } |
| | | |
| | | $table->add('title', sprintf('<label for="%s">%s</label>', $colprop['id'], Q($label))); |
| | | $table->add(null, $value); |
| | | if ($edit_mode) |
| | | $content .= html::p('addfield', $select_add->show(null)); |
| | | |
| | | $out .= html::tag('fieldset', $attrib, (!empty($fieldset['name']) ? html::tag('legend', null, Q($fieldset['name'])) : '') . $content) ."\n"; |
| | | continue; |
| | | } |
| | | $content = $table->show(); |
| | | |
| | | $content = ''; |
| | | if (is_array($fieldset['content'])) { |
| | | foreach ($fieldset['content'] as $col => $colprop) { |
| | | // remove subtype part of col name |
| | | list($field, $subtype) = explode(':', $col); |
| | | if (!$subtype) $subtype = 'home'; |
| | | $fullkey = $col.':'.$subtype; |
| | | |
| | | // skip cols unknown to the backend |
| | | if (!$coltypes[$field]) |
| | | continue; |
| | | |
| | | // merge colprop with global coltype configuration |
| | | $colprop += $coltypes[$field]; |
| | | $label = isset($colprop['label']) ? $colprop['label'] : rcube_label($col); |
| | | |
| | | // prepare subtype selector in edit mode |
| | | if ($edit_mode && is_array($colprop['subtypes'])) { |
| | | $select_subtype = new html_select(array('name' => '_subtype_'.$col.'[]', 'class' => 'contactselectsubtype')); |
| | | $select_subtype->add($colprop['subtypes']); |
| | | } |
| | | else |
| | | $select_subtype = null; |
| | | |
| | | if (!empty($colprop['value'])) { |
| | | $values = (array)$colprop['value']; |
| | | } |
| | | else { |
| | | // iterate over possible subtypes and collect values with their subtype |
| | | if (is_array($colprop['subtypes'])) { |
| | | $values = $subtypes = array(); |
| | | foreach ($colprop['subtypes'] as $i => $st) { |
| | | $newval = false; |
| | | if ($record[$field.':'.$st]) { |
| | | $subtypes[count($values)] = $st; |
| | | $newval = $record[$field.':'.$st]; |
| | | } |
| | | else if ($i == 0 && $record[$field]) { |
| | | $subtypes[count($values)] = $st; |
| | | $newval = $record[$field]; |
| | | } |
| | | if ($newval !== false) { |
| | | if (is_array($newval) && isset($newval[0])) |
| | | $values = array_merge($values, $newval); |
| | | else |
| | | $values[] = $newval; |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | $values = $record[$fullkey] ? $record[$fullkey] : $record[$field]; |
| | | $subtypes = null; |
| | | } |
| | | } |
| | | |
| | | // hack: create empty values array to force this field to be displayed |
| | | if (empty($values) && $colprop['visible']) |
| | | $values[] = ''; |
| | | |
| | | $rows = ''; |
| | | foreach ((array)$values as $i => $val) { |
| | | if ($subtypes[$i]) |
| | | $subtype = $subtypes[$i]; |
| | | |
| | | // render composite field |
| | | if ($colprop['type'] == 'composite') { |
| | | $composite = array(); $j = 0; |
| | | $template = $RCMAIL->config->get($col . '_template', '{'.join('} {', array_keys($colprop['childs'])).'}'); |
| | | foreach ($colprop['childs'] as $childcol => $cp) { |
| | | $childvalue = $val[$childcol] ? $val[$childcol] : $val[$j]; |
| | | |
| | | if ($edit_mode) { |
| | | if ($colprop['subtypes'] || $colprop['limit'] != 1) $cp['array'] = true; |
| | | $composite['{'.$childcol.'}'] = rcmail_get_edit_field($childcol, $childvalue, $cp, $cp['type']) . " "; |
| | | } |
| | | else { |
| | | $childval = $cp['render_func'] ? call_user_func($cp['render_func'], $childvalue, $childcol) : Q($childvalue); |
| | | $composite['{'.$childcol.'}'] = html::span('data ' . $childcol, $childval) . " "; |
| | | } |
| | | $j++; |
| | | } |
| | | |
| | | $coltypes[$field] += (array)$colprop; |
| | | $coltypes[$field]['count']++; |
| | | $val = strtr($template, $composite); |
| | | } |
| | | else if ($edit_mode) { |
| | | // call callback to render/format value |
| | | if ($colprop['render_func']) |
| | | $val = call_user_func($colprop['render_func'], $val, $col); |
| | | |
| | | $coltypes[$field] = (array)$colprop + $coltypes[$field]; |
| | | |
| | | if ($colprop['subtypes'] || $colprop['limit'] != 1) |
| | | $colprop['array'] = true; |
| | | |
| | | $val = rcmail_get_edit_field($col, $val, $colprop, $colprop['type']); |
| | | $coltypes[$field]['count']++; |
| | | } |
| | | else if ($colprop['render_func']) |
| | | $val = call_user_func($colprop['render_func'], $val, $col); |
| | | else if (is_array($colprop['options']) && isset($colprop['options'][$val])) |
| | | $val = $colprop['options'][$val]; |
| | | else |
| | | $val = Q($val); |
| | | |
| | | // use subtype as label |
| | | if ($colprop['subtypes']) |
| | | $label = $subtype; |
| | | |
| | | // add delete button/link |
| | | if ($edit_mode && !($colprop['visible'] && $colprop['limit'] == 1)) |
| | | $val .= html::a(array('href' => '#del', 'class' => 'contactfieldbutton deletebutton', 'title' => rcube_label('delete'), 'rel' => $col), $del_button); |
| | | |
| | | // display row with label |
| | | if ($label) { |
| | | $rows .= html::div('row', |
| | | html::div('contactfieldlabel label', $select_subtype ? $select_subtype->show($subtype) : Q($label)) . |
| | | html::div('contactfieldcontent '.$colprop['type'], $val)); |
| | | } |
| | | else // row without label |
| | | $rows .= html::div('row', html::div('contactfield', $val)); |
| | | } |
| | | |
| | | // add option to the add-field menu |
| | | if (!$colprop['limit'] || $coltypes[$field]['count'] < $colprop['limit']) { |
| | | $select_add->add($colprop['label'], $col); |
| | | $select_add->_count++; |
| | | } |
| | | |
| | | // wrap rows in fieldgroup container |
| | | $content .= html::tag('fieldset', array('class' => 'contactfieldgroup contactcontroller' . $col, 'style' => ($rows ? null : 'display:none')), |
| | | ($colprop['subtypes'] ? html::tag('legend', null, Q($colprop['label'])) : ' ') . |
| | | $rows); |
| | | } |
| | | |
| | | // also render add-field selector |
| | | if ($edit_mode) |
| | | $content .= html::p('addfield', $select_add->show(null, array('style' => $select_add->_count ? null : 'display:none'))); |
| | | |
| | | $content = html::div(array('id' => 'contactsection' . $section), $content); |
| | | } |
| | | else { |
| | | $content = $fieldset['content']; |
| | |
| | | $out .= html::tag('fieldset', null, html::tag('legend', null, Q($fieldset['name'])) . $content) ."\n"; |
| | | } |
| | | |
| | | if ($edit_mode) { |
| | | $RCMAIL->output->set_env('coltypes', $coltypes + $coltype_lables); |
| | | $RCMAIL->output->set_env('delbutton', $del_button); |
| | | $RCMAIL->output->add_label('delete'); |
| | | } |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | |
| | | function rcmail_contact_photo($attrib) |
| | | { |
| | | global $CONTACTS, $CONTACT_COLTYPES, $RCMAIL, $CONFIG; |
| | | |
| | | if ($result = $CONTACTS->get_result()) |
| | | $record = $result->first(); |
| | | |
| | | $photo_img = $attrib['placeholder'] ? $CONFIG['skin_path'] . $attrib['placeholder'] : 'program/blank.gif'; |
| | | unset($attrib['placeholder']); |
| | | |
| | | if ($CONTACT_COLTYPES['photo']) { |
| | | $RCMAIL->output->set_env('photo_placeholder', $photo_img); |
| | | |
| | | if ($record['photo']) |
| | | $photo_img = $RCMAIL->url(array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $_REQUEST['_source'])); |
| | | $img = html::img(array('src' => $photo_img, 'border' => 1, 'alt' => '')); |
| | | $content = html::div($attrib, $img); |
| | | |
| | | if ($RCMAIL->action == 'edit' || $RCMAIL->action == 'add') { |
| | | $RCMAIL->output->add_gui_object('contactphoto', $attrib['id']); |
| | | $hidden = new html_hiddenfield(array('name' => '_photo', 'id' => 'ff_photo')); |
| | | $content .= $hidden->show(); |
| | | } |
| | | } |
| | | |
| | | return $content; |
| | | } |
| | | |
| | | |
| | | function rcmail_format_date_col($val) |
| | | { |
| | | global $RCMAIL; |
| | | return format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d')); |
| | | } |
| | | |
| | | |
| | |
| | | // register action aliases |
| | | $RCMAIL->register_action_map(array( |
| | | 'add' => 'edit.inc', |
| | | 'photo' => 'show.inc', |
| | | 'upload-photo' => 'save.inc', |
| | | 'group-create' => 'groups.inc', |
| | | 'group-rename' => 'groups.inc', |
| | | 'group-delete' => 'groups.inc', |
| | |
| | | |
| | | if ($created && $OUTPUT->ajax_call) { |
| | | $OUTPUT->show_message('groupcreated', 'confirmation'); |
| | | $OUTPUT->command('insert_contact_group', array( |
| | | 'source' => $source, 'id' => $created['id'], 'name' => $created['name'])); |
| | | $OUTPUT->command('insert_contact_group', array('source' => $source) + $created); |
| | | } |
| | | else if (!$created) { |
| | | $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error'); |
| | |
| | | } |
| | | } |
| | | |
| | | $a_record = array( |
| | | 'name' => $vcard->displayname, |
| | | 'firstname' => $vcard->firstname, |
| | | 'surname' => $vcard->surname, |
| | | 'email' => $email, |
| | | 'vcard' => $vcard->export(), |
| | | ); |
| | | $a_record = $vcard->get_assoc(); |
| | | $a_record['vcard'] = $vcard->export(); |
| | | |
| | | $plugin = $RCMAIL->plugins->exec_hook('contact_create', array('record' => $a_record, 'source' => null)); |
| | | $a_record = $plugin['record']; |
| | |
| | | */ |
| | | |
| | | // get contacts for this user |
| | | $result = $CONTACTS->list_records(); |
| | | $result = $CONTACTS->list_records(array('name')); |
| | | |
| | | // update message count display |
| | | $OUTPUT->set_env('pagecount', ceil($result->count / $CONTACTS->page_size)); |
| | |
| | | $CONTACTS->set_pagesize(100); |
| | | $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid); |
| | | |
| | | while (is_object($recipients) && ($rec = $recipients->iterate())) |
| | | $mailto[] = format_email_recipient($rec['email'], $rec['name']); |
| | | while (is_object($recipients) && ($rec = $recipients->iterate())) { |
| | | $emails = $CONTACTS->get_col_values('email', $rec, true); |
| | | $mailto[] = format_email_recipient($emails[0], $rec['name']); |
| | | } |
| | | } |
| | | |
| | | if (!empty($mailto)) |
| | |
| | | | program/steps/addressbook/save.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: | |
| | |
| | | return; |
| | | } |
| | | |
| | | // Basic input checks |
| | | if ((!get_input_value('_name', RCUBE_INPUT_POST) || !get_input_value('_email', RCUBE_INPUT_POST))) { |
| | | |
| | | // handle photo upload for contacts |
| | | if ($RCMAIL->action == 'upload-photo') { |
| | | // clear all stored output properties (like scripts and env vars) |
| | | $OUTPUT->reset(); |
| | | |
| | | if ($filepath = $_FILES['_photo']['tmp_name']) { |
| | | // check file type and resize image |
| | | $imageprop = rcmail::imageprops($_FILES['_photo']['tmp_name']); |
| | | |
| | | if ($imageprop['width'] && $imageprop['height']) { |
| | | $maxsize = intval($RCMAIL->config->get('contact_photo_size', 160)); |
| | | $tmpfname = tempnam($RCMAIL->config->get('temp_dir'), 'rcmImgConvert'); |
| | | $save_hook = 'attachment_upload'; |
| | | |
| | | // scale image to a maximum size |
| | | if (($imageprop['width'] > $maxsize || $imageprop['height'] > $maxsize) && |
| | | (rcmail::imageconvert(array('in' => $filepath, 'out' => $tmpfname, 'size' => $maxsize.'x'.$maxsize, 'type' => $imageprop['type'])) !== false)) { |
| | | $filepath = $tmpfname; |
| | | $save_hook = 'attachment_save'; |
| | | } |
| | | |
| | | // save uploaded file in storage backend |
| | | $attachment = $RCMAIL->plugins->exec_hook($save_hook, array( |
| | | 'path' => $filepath, |
| | | 'size' => $_FILES['_photo']['size'], |
| | | 'name' => $_FILES['_photo']['name'], |
| | | 'mimetype' => 'image/' . $imageprop['type'], |
| | | )); |
| | | } |
| | | else |
| | | $attachment['error'] = rcube_label('invalidimageformat'); |
| | | |
| | | if ($attachment['status'] && !$attachment['abort']) { |
| | | $file_id = $attachment['id']; |
| | | $_SESSION['contacts']['files'][$file_id] = $attachment; |
| | | $OUTPUT->command('replace_contact_photo', $file_id); |
| | | } |
| | | else { // upload failed |
| | | $err = $_FILES['_photo']['error']; |
| | | if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) |
| | | $msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array('size' => show_bytes(parse_bytes(ini_get('upload_max_filesize')))))); |
| | | else if ($attachment['error']) |
| | | $msg = $attachment['error']; |
| | | else |
| | | $msg = rcube_label('fileuploaderror'); |
| | | |
| | | $OUTPUT->command('display_message', $msg, 'error'); |
| | | } |
| | | } |
| | | else if ($_SERVER['REQUEST_METHOD'] == 'POST') { |
| | | // if filesize exceeds post_max_size then $_FILES array is empty, |
| | | // show filesizeerror instead of fileuploaderror |
| | | if ($maxsize = ini_get('post_max_size')) |
| | | $msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array('size' => show_bytes(parse_bytes($maxsize))))); |
| | | else |
| | | $msg = rcube_label('fileuploaderror'); |
| | | |
| | | $OUTPUT->command('display_message', $msg, 'error'); |
| | | } |
| | | |
| | | $OUTPUT->command('photo_upload_end'); |
| | | $OUTPUT->send('iframe'); |
| | | } |
| | | |
| | | |
| | | // read POST values into hash array |
| | | $a_record = array(); |
| | | foreach ($GLOBALS['CONTACT_COLTYPES'] as $col => $colprop) { |
| | | $fname = '_'.$col; |
| | | if ($colprop['composite']) |
| | | continue; |
| | | // gather form data of composite fields |
| | | if ($colprop['childs']) { |
| | | $values = array(); |
| | | foreach ($colprop['childs'] as $childcol => $cp) { |
| | | $vals = get_input_value('_'.$childcol, RCUBE_INPUT_POST); |
| | | foreach ((array)$vals as $i => $val) |
| | | $values[$i][$childcol] = $val; |
| | | } |
| | | $subtypes = get_input_value('_subtype_' . $col, RCUBE_INPUT_POST); |
| | | foreach ($subtypes as $i => $subtype) |
| | | if ($values[$i]) |
| | | $a_record[$col.':'.$subtype][] = $values[$i]; |
| | | } |
| | | // assign values and subtypes |
| | | else if (is_array($_POST[$fname])) { |
| | | $values = get_input_value($fname, RCUBE_INPUT_POST); |
| | | $subtypes = get_input_value('_subtype_' . $col, RCUBE_INPUT_POST); |
| | | foreach ($values as $i => $val) { |
| | | $subtype = $subtypes[$i] ? ':'.$subtypes[$i] : ''; |
| | | $a_record[$col.$subtype][] = $val; |
| | | } |
| | | } |
| | | else if (isset($_POST[$fname])) { |
| | | $a_record[$col] = get_input_value($fname, RCUBE_INPUT_POST); |
| | | } |
| | | } |
| | | |
| | | if (empty($a_record['name'])) |
| | | $a_record['name'] = join(' ', array_filter(array($a_record['prefix'], $a_record['firstname'], $a_record['middlename'], $a_record['surname'], $a_record['suffix'],))); |
| | | |
| | | #var_dump($a_record); |
| | | |
| | | // Basic input checks (TODO: delegate to $CONTACTS instance) |
| | | if (empty($a_record['name'])/* || empty($a_record['email'])*/) { |
| | | $OUTPUT->show_message('formincomplete', 'warning'); |
| | | rcmail_overwrite_action($return_action); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // setup some vars we need |
| | | $a_save_cols = array('name', 'firstname', 'surname', 'email'); |
| | | $a_record = array(); |
| | | |
| | | // read POST values into hash array |
| | | foreach ($a_save_cols as $col) { |
| | | $fname = '_'.$col; |
| | | if (isset($_POST[$fname])) |
| | | $a_record[$col] = get_input_value($fname, RCUBE_INPUT_POST); |
| | | } |
| | | |
| | | // Validity checks |
| | | $_email = idn_to_ascii($a_record['email']); |
| | | foreach ($CONTACTS->get_col_values('email', $a_record, true) as $email) { |
| | | if (strlen($email)) { |
| | | $_email = idn_to_ascii($email); |
| | | if (!check_email($_email, false)) { |
| | | $OUTPUT->show_message('emailformaterror', 'warning', array('email' => $_email)); |
| | | $OUTPUT->show_message('emailformaterror', 'warning', array('email' => $email)); |
| | | rcmail_overwrite_action($return_action); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // get raw photo data if changed |
| | | if (isset($a_record['photo'])) { |
| | | if ($a_record['photo'] == '-del-') { |
| | | $a_record['photo'] = ''; |
| | | } |
| | | else if ($tempfile = $_SESSION['contacts']['files'][$a_record['photo']]) { |
| | | $tempfile = $RCMAIL->plugins->exec_hook('attachment_get', $tempfile); |
| | | if ($tempfile['status']) |
| | | $a_record['photo'] = $tempfile['data'] ? $tempfile['data'] : @file_get_contents($tempfile['path']); |
| | | } |
| | | else |
| | | unset($a_record['photo']); |
| | | |
| | | // cleanup session data |
| | | $RCMAIL->plugins->exec_hook('attachments_cleanup', array()); |
| | | $RCMAIL->session->remove('contacts'); |
| | | } |
| | | |
| | | // update an existing contact |
| | |
| | | } |
| | | else { |
| | | // show error message |
| | | $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error', null, false); |
| | | $err = $CONTACTS->get_error(); |
| | | $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : ($err['message'] ? $err['message'] : 'errorsaving'), 'error', null, false); |
| | | rcmail_overwrite_action('show'); |
| | | } |
| | | } |
| | |
| | | // insert a new contact |
| | | else { |
| | | // check for existing contacts |
| | | $existing = $CONTACTS->search('email', $a_record['email'], true, false); |
| | | $existing = false; |
| | | foreach ($CONTACTS->get_col_values('email', $a_record, true) as $email) { |
| | | if (($res = $CONTACTS->search('email', $email, true, false)) && $res->count) { |
| | | $existing = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // show warning message |
| | | if ($existing->count) { |
| | | if ($existing) { |
| | | $OUTPUT->show_message('contactexists', 'warning', null, false); |
| | | rcmail_overwrite_action('add'); |
| | | return; |
| | |
| | | } |
| | | else { |
| | | // show error message |
| | | $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error', null, false); |
| | | $err = $CONTACTS->get_error(); |
| | | $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : ($err['message'] ? $err['message'] : 'errorsaving'), 'error', null, false); |
| | | rcmail_overwrite_action('add'); |
| | | } |
| | | } |
| | |
| | | | program/steps/addressbook/search.inc | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2007, The Roundcube Dev Team | |
| | | | Copyright (C) 2005-2011, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | // get contacts for this user |
| | | $result = $CONTACTS->search(array('name','email'), $search); |
| | | |
| | | if ($result->count > 0) |
| | | { |
| | | // save search settings in session |
| | | $_SESSION['search'][$search_request] = $CONTACTS->get_search_set(); |
| | | |
| | | if ($result->count > 0) |
| | | { |
| | | // create javascript list |
| | | rcmail_js_contacts_list($result); |
| | | } |
| | |
| | | $OUTPUT->set_env('cid', $record['ID']); |
| | | } |
| | | |
| | | // return raw photo of the given contact |
| | | if ($RCMAIL->action == 'photo') { |
| | | if (($file_id = get_input_value('_photo', RCUBE_INPUT_GPC)) && ($tempfile = $_SESSION['contacts']['files'][$file_id])) { |
| | | $tempfile = $RCMAIL->plugins->exec_hook('attachment_display', $tempfile); |
| | | if ($tempfile['status']) { |
| | | if ($tempfile['data']) |
| | | $data = $tempfile['data']; |
| | | else if ($tempfile['path']) |
| | | $data = file_get_contents($tempfile['path']); |
| | | } |
| | | } |
| | | else if ($record['photo']) { |
| | | $data = is_array($record['photo']) ? $record['photo'][0] : $record['photo']; |
| | | if (!preg_match('![^a-z0-9/=+-]!i', $data)) |
| | | $data = base64_decode($data, true); |
| | | } |
| | | |
| | | function rcmail_contact_details($attrib) |
| | | header('Content-Type: ' . rc_image_content_type($data)); |
| | | echo $data ? $data : file_get_contents('program/blank.gif'); |
| | | exit; |
| | | } |
| | | |
| | | |
| | | function rcmail_contact_head($attrib) |
| | | { |
| | | global $CONTACTS, $RCMAIL; |
| | | |
| | |
| | | return false; |
| | | } |
| | | |
| | | $i_size = !empty($attrib['size']) ? $attrib['size'] : 40; |
| | | $t_rows = !empty($attrib['textarearows']) ? $attrib['textarearows'] : 6; |
| | | $t_cols = !empty($attrib['textareacols']) ? $attrib['textareacols'] : 40; |
| | | |
| | | $microformats = array('name' => 'fn', 'email' => 'email'); |
| | | |
| | | $form = array( |
| | | 'head' => array( // section 'head' is magic! |
| | | 'content' => array( |
| | | 'prefix' => array('type' => 'text'), |
| | | 'firstname' => array('type' => 'text'), |
| | | 'middlename' => array('type' => 'text'), |
| | | 'surname' => array('type' => 'text'), |
| | | 'suffix' => array('type' => 'text'), |
| | | ), |
| | | ), |
| | | ); |
| | | |
| | | unset($attrib['name']); |
| | | return rcmail_contact_form($form, $record, $attrib); |
| | | } |
| | | |
| | | |
| | | function rcmail_contact_details($attrib) |
| | | { |
| | | global $CONTACTS, $RCMAIL, $CONTACT_COLTYPES; |
| | | |
| | | // check if we have a valid result |
| | | if (!(($result = $CONTACTS->get_result()) && ($record = $result->first()))) { |
| | | //$RCMAIL->output->show_message('contactnotfound'); |
| | | return false; |
| | | } |
| | | |
| | | $i_size = !empty($attrib['size']) ? $attrib['size'] : 40; |
| | | |
| | | $form = array( |
| | | 'info' => array( |
| | | 'name' => rcube_label('contactproperties'), |
| | | 'content' => array( |
| | | 'name' => array('type' => 'text', 'size' => $i_size), |
| | | 'firstname' => array('type' => 'text', 'size' => $i_size), |
| | | 'surname' => array('type' => 'text', 'size' => $i_size), |
| | | 'email' => array('type' => 'text', 'size' => $i_size), |
| | | 'gender' => array('size' => $i_size), |
| | | 'maidenname' => array('size' => $i_size), |
| | | 'email' => array('size' => $i_size, 'render_func' => 'rcmail_render_email_value'), |
| | | 'phone' => array('size' => $i_size), |
| | | 'address' => array(), |
| | | 'birthday' => array('size' => $i_size), |
| | | 'anniversary' => array('size' => $i_size), |
| | | 'website' => array('size' => $i_size, 'render_func' => 'rcmail_render_url_value'), |
| | | 'im' => array('size' => $i_size), |
| | | 'manager' => array('size' => $i_size), |
| | | 'assistant' => array('size' => $i_size), |
| | | 'spouse' => array('size' => $i_size), |
| | | ), |
| | | ), |
| | | 'groups' => array( |
| | | 'name' => rcube_label('groups'), |
| | | 'content' => '', |
| | | ), |
| | | ); |
| | | |
| | | // Get content of groups fieldset |
| | | if ($groups = rcmail_contact_record_groups($record['ID'])) { |
| | | $form['groups']['content'] = $groups; |
| | | } |
| | | else { |
| | | unset($form['groups']); |
| | | if (isset($CONTACT_COLTYPES['notes'])) { |
| | | $form['notes'] = array( |
| | | 'name' => rcube_label('notes'), |
| | | 'content' => array( |
| | | 'notes' => array('type' => 'textarea', 'label' => false), |
| | | ), |
| | | ); |
| | | } |
| | | |
| | | if (!empty($record['email'])) { |
| | | $form['info']['content']['email']['value'] = html::a(array( |
| | | 'href' => 'mailto:' . $record['email'], |
| | | 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($record['email'])), |
| | | 'title' => rcube_label('composeto'), |
| | | 'class' => $microformats['email'], |
| | | ), Q($record['email'])); |
| | | } |
| | | foreach (array('name', 'firstname', 'surname') as $col) { |
| | | if ($record[$col]) { |
| | | $form['info']['content'][$col]['value'] = html::span($microformats[$col], Q($record[$col])); |
| | | } |
| | | if ($CONTACTS->groups) { |
| | | $form['groups'] = array( |
| | | 'name' => rcube_label('groups'), |
| | | 'content' => rcmail_contact_record_groups($record['ID']), |
| | | ); |
| | | } |
| | | |
| | | return rcmail_contact_form($form, $record); |
| | | } |
| | | |
| | | |
| | | function rcmail_render_email_value($email, $col) |
| | | { |
| | | return html::a(array( |
| | | 'href' => 'mailto:' . $email, |
| | | 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($email)), |
| | | 'title' => rcube_label('composeto'), |
| | | 'class' => 'email', |
| | | ), Q($email)); |
| | | } |
| | | |
| | | |
| | | function rcmail_render_url_value($url, $col) |
| | | { |
| | | $prefix = preg_match('![htfps]+://!', $url) ? '' : 'http://'; |
| | | return html::a(array( |
| | | 'href' => $prefix . $url, |
| | | 'target' => '_blank', |
| | | 'class' => 'url', |
| | | ), Q($url)); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | //$OUTPUT->framed = $_framed; |
| | | $OUTPUT->add_handler('contacthead', 'rcmail_contact_head'); |
| | | $OUTPUT->add_handler('contactdetails', 'rcmail_contact_details'); |
| | | $OUTPUT->add_handler('contactphoto', 'rcmail_contact_photo'); |
| | | |
| | | $OUTPUT->send('contact'); |
| | |
| | | $abook->set_group($gid); |
| | | $abook->set_pagesize(1000); // TODO: limit number of group members by config |
| | | $result = $abook->list_records(array('email','name')); |
| | | while ($result && ($sql_arr = $result->iterate())) |
| | | $members[] = format_email_recipient($sql_arr['email'], $sql_arr['name']); |
| | | while ($result && ($sql_arr = $result->iterate())) { |
| | | foreach ((array)$sql_arr['email'] as $email) |
| | | $members[] = format_email_recipient($email, $sql_arr['name']); |
| | | } |
| | | |
| | | $OUTPUT->command('replace_group_recipients', $gid, join(', ', $members)); |
| | | } |
| | |
| | | |
| | | if ($result = $abook->search(array('email','name'), $search, false, true, true, 'email')) { |
| | | while ($sql_arr = $result->iterate()) { |
| | | $contact = format_email_recipient($sql_arr['email'], $sql_arr['name']); |
| | | foreach ((array)$abook->get_col_values('email', $sql_arr, true) as $email) { |
| | | $contact = format_email_recipient($email, $sql_arr['name']); |
| | | // when we've got more than one book, we need to skip duplicates |
| | | if ($books_num == 1 || !in_array($contact, $contacts)) { |
| | | $contacts[] = $contact; |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // also list matching contact groups |
| | | if ($abook->groups) { |
| | |
| | | |
| | | $out = html::div($attrib, |
| | | $OUTPUT->form_tag(array('name' => 'uploadform', 'method' => 'post', 'enctype' => 'multipart/form-data'), |
| | | html::div(null, rcmail_compose_attachment_field(array('size' => $attrib[attachmentfieldsize]))) . |
| | | html::div(null, rcmail_compose_attachment_field(array('size' => $attrib['attachmentfieldsize']))) . |
| | | html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . |
| | | html::div('buttons', |
| | | $button->show(rcube_label('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . |
| | |
| | | text-align: right; |
| | | } |
| | | |
| | | #contacttabs |
| | | { |
| | | position: relative; |
| | | padding-bottom: 22px; |
| | | } |
| | | |
| | | #contacttabs div.tabsbar { |
| | | top: 0; |
| | | left: 2px; |
| | | } |
| | | |
| | | #contacttabs fieldset.tabbed { |
| | | position: relative; |
| | | top: 22px; |
| | | min-height: 5em; |
| | | } |
| | | |
| | | #contacthead |
| | | { |
| | | margin-bottom: 1em; |
| | | border: 0; |
| | | padding: 0; |
| | | } |
| | | |
| | | #contacthead .names span.namefield, |
| | | #contacthead .names input |
| | | { |
| | | font-size: 140%; |
| | | } |
| | | |
| | | #contacthead .displayname span.namefield |
| | | { |
| | | font-size: 120%; |
| | | } |
| | | |
| | | #contacthead span.nickname:before, |
| | | #contacthead span.nickname:after, |
| | | #contacthead input.ff_nickname:before, |
| | | #contacthead input.ff_nickname:after |
| | | { |
| | | content: '"'; |
| | | } |
| | | |
| | | #contacthead input |
| | | { |
| | | margin-right: 6px; |
| | | margin-bottom: 0.2em; |
| | | } |
| | | |
| | | #contacthead .names input, |
| | | #contacthead .addnames input, |
| | | #contacthead .jobnames input |
| | | { |
| | | width: 180px; |
| | | } |
| | | |
| | | #contacthead input.ff_prefix, |
| | | #contacthead input.ff_suffix |
| | | { |
| | | width: 90px; |
| | | } |
| | | |
| | | #contacthead .addnames input.ff_name |
| | | { |
| | | width: 374px; |
| | | } |
| | | |
| | | #contactphoto |
| | | { |
| | | float: right; |
| | | width: 60px; |
| | | margin-left: 3em; |
| | | margin-right: 4px; |
| | | } |
| | | |
| | | #contactpic |
| | | { |
| | | width: 60px; |
| | | min-height: 60px; |
| | | border: 1px solid #ccc; |
| | | background: white; |
| | | } |
| | | |
| | | #contactpic img { |
| | | width: 60px; |
| | | } |
| | | |
| | | #contactphoto .formlinks |
| | | { |
| | | margin-top: 0.5em; |
| | | text-align: center; |
| | | } |
| | | |
| | | fieldset.contactfieldgroup |
| | | { |
| | | border: 0; |
| | | margin: 0.5em 0; |
| | | padding: 0.5em 2px; |
| | | } |
| | | |
| | | fieldset.contactfieldgroup legend |
| | | { |
| | | font-size: 0.9em; |
| | | } |
| | | |
| | | .contactfieldgroup .row |
| | | { |
| | | position: relative; |
| | | margin-bottom: 0.4em; |
| | | } |
| | | |
| | | .contactfieldgroup .contactfieldlabel |
| | | { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 2px; |
| | | width: 90px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | color: #666; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .contactfieldgroup .contactfieldlabel select |
| | | { |
| | | width: 78px; |
| | | background: none; |
| | | border: 0; |
| | | color: #666; |
| | | font-weight: bold; |
| | | padding-left: 0; |
| | | } |
| | | |
| | | .contactfieldgroup .contactfieldcontent |
| | | { |
| | | padding-left: 100px; |
| | | min-height: 1em; |
| | | line-height: 1.3em; |
| | | } |
| | | |
| | | .contactfieldgroup .contactfield { |
| | | line-height: 1.3em; |
| | | } |
| | | |
| | | .contactcontrolleraddress .contactfieldcontent input { |
| | | margin-bottom: 0.1em; |
| | | } |
| | | |
| | | .contactfieldcontent .contactfieldbutton { |
| | | vertical-align: middle; |
| | | margin-left: 0.5em; |
| | | } |
| | | |
| | | #upload-form |
| | | { |
| | | padding: 6px; |
| | | } |
| | | |
| | | #upload-form div |
| | | { |
| | | padding: 2px; |
| | | } |
| | |
| | | padding: 1px 3px; |
| | | } |
| | | |
| | | input.placeholder, |
| | | textarea.placeholder |
| | | { |
| | | color: #aaa; |
| | | } |
| | | |
| | | input.button |
| | | { |
| | | height: 20px; |
| | |
| | | font-size: 11px; |
| | | } |
| | | |
| | | .formlinks a, |
| | | .formlinks a:visited |
| | | { |
| | | color: #CC0000; |
| | | font-size: 11px; |
| | | text-decoration: none; |
| | | } |
| | | |
| | | .formlinks a.disabled, |
| | | .formlinks a.disabled:visited |
| | | { |
| | | color: #999999; |
| | | } |
| | | |
| | | /** common user interface objects */ |
| | | |
| | | #mainscreen |
| | |
| | | // Warning: don't place "caller" <script> inside page element (id) |
| | | function rcube_init_tabs(id, current) |
| | | { |
| | | var content = document.getElementById(id), |
| | | // get fieldsets of the higher-level (skip nested fieldsets) |
| | | fs = $('fieldset', content).not('fieldset > fieldset'); |
| | | var content = $('#'+id), |
| | | fs = content.children('fieldset'); |
| | | |
| | | if (!fs.length) |
| | | return; |
| | |
| | | |
| | | // convert fildsets into tabs |
| | | fs.each(function(idx) { |
| | | var tab, a, elm = $(this), |
| | | // get first legend element |
| | | legend = $(elm).children('legend'); |
| | | var tab, a, elm = $(this), legend = elm.children('legend'); |
| | | |
| | | // create a tab |
| | | a = $('<a>').text(legend.text()).attr('href', '#'); |
| | |
| | | |
| | | function rcube_show_tab(id, index) |
| | | { |
| | | var content = document.getElementById(id), |
| | | fs = $('fieldset', content).not('fieldset > fieldset'); |
| | | var fs = $('#'+id).children('fieldset'); |
| | | |
| | | fs.each(function(idx) { |
| | | // Show/hide fieldset (tab content) |
| | |
| | | mailboxmenu: {id:'mailboxoptionsmenu', above:1}, |
| | | composemenu: {id:'composeoptionsmenu', editable:1}, |
| | | // toggle: #1486823, #1486930 |
| | | uploadmenu: {id:'attachment-form', editable:1, above:1, toggle:!bw.ie&&!bw.linux } |
| | | uploadmenu: {id:'attachment-form', editable:1, above:1, toggle:!bw.ie&&!bw.linux }, |
| | | uploadform: {id:'upload-form', editable:1, toggle:!bw.ie&&!bw.linux } |
| | | }; |
| | | |
| | | var obj; |
| | |
| | | |
| | | if (!above && pos.top + ref.offsetHeight + obj.height() > window.innerHeight) |
| | | above = true; |
| | | |
| | | if (pos.left + obj.width() > window.innerWidth) |
| | | pos.left = window.innerWidth - obj.width() - 30; |
| | | |
| | | obj.css({ left:pos.left, top:(pos.top + (above ? -obj.height() : ref.offsetHeight)) }); |
| | | } |
| | |
| | | if (rcmail.env.action == 'compose') |
| | | rcmail_ui.init_compose_form(); |
| | | } |
| | | else if (rcmail.env.task == 'addressbook') { |
| | | rcmail.addEventListener('afterupload-photo', function(){ rcmail_ui.show_popup('uploadform', false); }); |
| | | } |
| | | } |
| | | |
| | | // Events handling in iframes (eg. preview pane) |
| | |
| | | { |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | .contactfieldgroup legend |
| | | { |
| | | padding: 0 0 0.5em 0; |
| | | margin-left: -4px; |
| | | } |
| | |
| | | display: none; |
| | | } |
| | | |
| | | .formlinks a, |
| | | .formlinks a:visited |
| | | { |
| | | color: #999999; |
| | | font-size: 11px; |
| | | text-decoration: none; |
| | | } |
| | | |
| | | .formlinks a, |
| | | .formlinks a:visited |
| | | { |
| | | color: #CC0000; |
| | | } |
| | | |
| | | #compose-editorfooter |
| | | { |
| | | position: absolute; |
| | |
| | | |
| | | <div id="contact-title" class="boxtitle"><roundcube:label name="contactproperties" /></div> |
| | | <div id="contact-details" class="boxcontent"> |
| | | <div id="contactphoto"><roundcube:object name="contactphoto" id="contactpic" placeholder="/images/contactpic.png" /></div> |
| | | <roundcube:object name="contacthead" id="contacthead" /> |
| | | <div style="clear:both"></div> |
| | | <div id="contacttabs"> |
| | | <roundcube:object name="contactdetails" /> |
| | | </div> |
| | | <p> |
| | | <roundcube:button command="edit" type="input" class="button" label="editcontact" condition="!ENV:readonly" /> |
| | | </p> |
| | | </div> |
| | | <script type="text/javascript">rcube_init_tabs('contact-details')</script> |
| | | <script type="text/javascript">rcube_init_tabs('contacttabs')</script> |
| | | |
| | | </body> |
| | | </html> |
| | |
| | | <roundcube:include file="/includes/links.html" /> |
| | | <script type="text/javascript" src="/functions.js"></script> |
| | | </head> |
| | | <body class="iframe"> |
| | | <body class="iframe" onload="rcube_init_mail_ui()"> |
| | | |
| | | <div id="contact-title" class="boxtitle"><roundcube:label name="addcontact" /></div> |
| | | <div id="contact-details" class="boxcontent"> |
| | | <roundcube:object name="contacteditform" size="40" /> |
| | | <form name="editform" method="post" action="./"> |
| | | <div id="contactphoto"> |
| | | <roundcube:object name="contactphoto" id="contactpic" placeholder="/images/contactpic.png" /> |
| | | <div class="formlinks"> |
| | | <roundcube:button command="upload-photo" id="uploadformlink" type="link" label="addphoto" class="disabled" classAct="active" onclick="rcmail_ui.show_popup('uploadform', true);return false" condition="env:photocol" /><br/> |
| | | <roundcube:button command="delete-photo" type="link" label="delete" class="disabled" classAct="active" condition="env:photocol" /> |
| | | </div> |
| | | </div> |
| | | <roundcube:object name="contactedithead" id="contacthead" size="16" form="editform" /> |
| | | <div style="clear:both"></div> |
| | | |
| | | <div id="contacttabs"> |
| | | <roundcube:object name="contacteditform" size="40" textareacols="60" deleteIcon="/images/icons/delete.png" form="editform" /> |
| | | </div> |
| | | <p> |
| | | <input type="button" value="<roundcube:label name="cancel" />" class="button" onclick="history.back()" /> |
| | | <roundcube:button command="save" type="input" class="button mainaction" label="save" /> |
| | | </p> |
| | | </form> |
| | | </div> |
| | | <script type="text/javascript">rcube_init_tabs('contact-details')</script> |
| | | |
| | | <roundcube:object name="photoUploadForm" id="upload-form" size="30" class="popupmenu" /> |
| | | |
| | | <script type="text/javascript">rcube_init_tabs('contacttabs')</script> |
| | | |
| | | </body> |
| | | </html> |
| | |
| | | <roundcube:include file="/includes/links.html" /> |
| | | <script type="text/javascript" src="/functions.js"></script> |
| | | </head> |
| | | <body class="iframe"> |
| | | <body class="iframe" onload="rcube_init_mail_ui()"> |
| | | |
| | | <div id="contact-title" class="boxtitle"><roundcube:label name="editcontact" /></div> |
| | | <div id="contact-details" class="boxcontent"> |
| | | <roundcube:object name="contacteditform" size="40" /> |
| | | <form name="editform" method="post" action="./"> |
| | | <div id="contactphoto"> |
| | | <roundcube:object name="contactphoto" id="contactpic" placeholder="/images/contactpic.png" /> |
| | | <div class="formlinks"> |
| | | <roundcube:button command="upload-photo" id="uploadformlink" type="link" label="replacephoto" class="disabled" classAct="active" onclick="rcmail_ui.show_popup('uploadform', true);return false" condition="env:photocol" /><br/> |
| | | <roundcube:button command="delete-photo" type="link" label="delete" class="disabled" classAct="active" condition="env:photocol" /> |
| | | </div> |
| | | </div> |
| | | <roundcube:object name="contactedithead" id="contacthead" size="16" form="editform" /> |
| | | <div style="clear:both"></div> |
| | | |
| | | <div id="contacttabs"> |
| | | <roundcube:object name="contacteditform" size="40" textareacols="60" deleteIcon="/images/icons/delete.png" form="editform" /> |
| | | </div> |
| | | <p> |
| | | <roundcube:button command="show" type="input" class="button" label="cancel" /> |
| | | <roundcube:button command="save" type="input" class="button mainaction" label="save" /> |
| | | </p> |
| | | </form> |
| | | </div> |
| | | <script type="text/javascript">rcube_init_tabs('contact-details')</script> |
| | | |
| | | <roundcube:object name="photoUploadForm" id="upload-form" size="30" class="popupmenu" /> |
| | | |
| | | <script type="text/javascript">rcube_init_tabs('contacttabs')</script> |
| | | |
| | | </body> |
| | | </html> |