- Added searching in all addressbook sources (global-search)
- Added addressbook source selection in contacts import
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Added searching in all addressbook sources |
| | | - Added addressbook source selection in contacts import |
| | | - Implement LDAPv3 Virtual List View (VLV) for paged results listing |
| | | - Use 'address_template' config option when adding a new address block (#1487944) |
| | | - Added addressbook advanced search |
| | |
| | | |
| | | // In order to enable public ldap search, configure an array like the Verisign |
| | | // example further below. if you would like to test, simply uncomment the example. |
| | | // Array key must contain only safe characters, ie. a-zA-Z0-9_ |
| | | $rcmail_config['ldap_public'] = array(); |
| | | |
| | | // If you are going to use LDAP for individual address books, you will need to |
| | |
| | | if (this.contact_list && this.contact_list.rowcount > 0) |
| | | this.enable_command('export', true); |
| | | |
| | | this.enable_command('add', 'import', !this.env.readonly); |
| | | this.enable_command('add', 'import', this.env.writable_source); |
| | | this.enable_command('list', 'listgroup', 'advanced-search', true); |
| | | break; |
| | | |
| | |
| | | this.reset_qsearch(); |
| | | |
| | | this.list_contacts(props); |
| | | this.enable_command('add', 'import', (this.env.address_sources && !this.env.address_sources[this.env.source].readonly)); |
| | | this.enable_command('add', 'import', this.env.writable_source); |
| | | } |
| | | break; |
| | | |
| | |
| | | |
| | | if (s && this.env.mailbox) |
| | | this.list_mailbox(this.env.mailbox); |
| | | else if (s && this.task == 'addressbook') |
| | | else if (s && this.task == 'addressbook') { |
| | | if (this.env.source == '') { |
| | | for (var n in this.env.address_sources) break; |
| | | this.env.source = n; |
| | | this.env.group = ''; |
| | | } |
| | | this.list_contacts(this.env.source, this.env.group); |
| | | } |
| | | break; |
| | | |
| | | case 'listgroup': |
| | |
| | | if (this.preview_timer) |
| | | clearTimeout(this.preview_timer); |
| | | |
| | | var id, frame, ref = this; |
| | | var n, id, sid, ref = this, writable = false, |
| | | source = this.env.source ? this.env.address_sources[this.env.source] : null; |
| | | |
| | | if (id = list.get_single_selection()) |
| | | this.preview_timer = window.setTimeout(function(){ ref.load_contact(id, 'show'); }, 200); |
| | | else if (this.env.contentframe) |
| | | this.show_contentframe(false); |
| | | |
| | | // no source = search result, we'll need to detect if any of |
| | | // selected contacts are in writable addressbook to enable edit/delete |
| | | if (list.selection.length) { |
| | | if (!source) { |
| | | for (n in list.selection) { |
| | | sid = String(list.selection[n]).replace(/^[^-]+-/, ''); |
| | | if (sid && this.env.address_sources[sid] && !this.env.address_sources[sid].readonly) { |
| | | writable = true; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | writable = !source.readonly; |
| | | } |
| | | } |
| | | |
| | | this.enable_command('compose', list.selection.length > 0); |
| | | this.enable_command('edit', (id && this.env.address_sources && !this.env.address_sources[this.env.source].readonly) ? true : false); |
| | | this.enable_command('delete', list.selection.length && this.env.address_sources && !this.env.address_sources[this.env.source].readonly); |
| | | this.enable_command('edit', id && writable); |
| | | this.enable_command('delete', list.selection.length && writable); |
| | | |
| | | return false; |
| | | }; |
| | |
| | | if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm'))) |
| | | return; |
| | | |
| | | var id, a_cids = [], qs = ''; |
| | | var id, n, a_cids = [], qs = ''; |
| | | |
| | | if (this.env.cid) |
| | | a_cids.push(this.env.cid); |
| | | else { |
| | | for (var n=0; n<selection.length; n++) { |
| | | for (n=0; n<selection.length; n++) { |
| | | id = selection[n]; |
| | | a_cids.push(id); |
| | | this.contact_list.remove_row(id, (n == selection.length-1)); |
| | |
| | | target = window.frames[this.env.contentframe]; |
| | | this.contact_list.clear_selection(); |
| | | } |
| | | else if (framed) |
| | | return false; |
| | | |
| | | this.location_href(this.env.comm_path+'&_action=search'+add_url |
| | | +'&_source='+urlencode(this.env.source) |
| | | +(this.env.group ? '&_gid='+urlencode(this.env.group) : ''), target); |
| | | this.location_href(this.env.comm_path+'&_action=search'+add_url, target); |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | // unselect directory/group |
| | | this.unselect_directory = function() |
| | | { |
| | | if (this.env.address_sources.length > 1 || this.env.group != '') { |
| | | this.select_folder('', (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source)); |
| | | this.env.group = ''; |
| | | this.env.source = ''; |
| | | } |
| | | }; |
| | | |
| | | |
| | |
| | | switch (response.action) { |
| | | case 'delete': |
| | | if (this.task == 'addressbook') { |
| | | var uid = this.contact_list.get_selection(); |
| | | var sid, uid = this.contact_list.get_selection(), writable = false; |
| | | |
| | | if (uid && this.contact_list.rows[uid]) { |
| | | // search results, get source ID from record ID |
| | | if (this.env.source == '') { |
| | | sid = String(uid).replace(/^[^-]+-/, ''); |
| | | writable = sid && this.env.address_sources[sid] && !this.env.address_sources[sid].readonly; |
| | | } |
| | | else { |
| | | writable = !this.env.address_sources[this.env.source].readonly; |
| | | } |
| | | } |
| | | this.enable_command('compose', (uid && this.contact_list.rows[uid])); |
| | | this.enable_command('delete', 'edit', (uid && this.contact_list.rows[uid] && this.env.address_sources && !this.env.address_sources[this.env.source].readonly)); |
| | | this.enable_command('delete', 'edit', writable); |
| | | this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); |
| | | } |
| | | |
| | |
| | | this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); |
| | | |
| | | if (response.action == 'list' || response.action == 'search') { |
| | | this.enable_command('group-create', |
| | | (this.env.address_sources[this.env.source].groups && !this.env.address_sources[this.env.source].readonly)); |
| | | this.enable_command('group-rename', 'group-delete', |
| | | (this.env.address_sources[this.env.source].groups && this.env.group && !this.env.address_sources[this.env.source].readonly)); |
| | | var source = this.env.source != '' ? this.env.address_sources[this.env.source] : null; |
| | | this.enable_command('group-create', (source && source.groups && !source.readonly)); |
| | | this.enable_command('group-rename', 'group-delete', (source && source.groups && this.env.group && !source.readonly)); |
| | | this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); |
| | | } |
| | | } |
| | |
| | | $labels['import'] = 'Import'; |
| | | $labels['importcontacts'] = 'Import contacts'; |
| | | $labels['importfromfile'] = 'Import from file:'; |
| | | $labels['importtarget'] = 'Add new contacts to address book:'; |
| | | $labels['importreplace'] = 'Replace the entire address book'; |
| | | $labels['importtext'] = 'You can upload contacts from an existing address book.<br/>We currently support importing addresses from the <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> data format.'; |
| | | $labels['done'] = 'Done'; |
| | |
| | | $labels['search'] = 'Szukaj'; |
| | | $labels['advsearch'] = 'Wyszukiwanie zaawansowane'; |
| | | $labels['other'] = 'Inne'; |
| | | $labels['importtarget'] = 'Dodaj nowe kontakty do książki adresowej:'; |
| | | |
| | | ?> |
| | |
| | | if (!$OUTPUT->ajax_call) |
| | | return; |
| | | |
| | | $cid = get_input_value('_cid', RCUBE_INPUT_POST); |
| | | |
| | | $cids = rcmail_get_cids(); |
| | | $target = get_input_value('_to', RCUBE_INPUT_POST); |
| | | $target_group = get_input_value('_togid', RCUBE_INPUT_POST); |
| | | |
| | | if ($cid && preg_match('/^[a-zA-Z0-9\+\/=_-]+(,[a-zA-Z0-9\+\/=_-]+)*$/', $cid) && strlen($target) && $target !== $source) |
| | | { |
| | | $success = 0; |
| | | $maxnum = $RCMAIL->config->get('max_group_members', 0); |
| | | |
| | | foreach ($cids as $source => $cid) |
| | | { |
| | | // Something wrong, target not specified |
| | | if (!strlen($target)) { |
| | | break; |
| | | } |
| | | |
| | | // It maight happen when copying records from search result |
| | | // Do nothing, go to next source |
| | | if ($target == $source) { |
| | | continue; |
| | | } |
| | | |
| | | $CONTACTS = $RCMAIL->get_address_book($source); |
| | | $TARGET = $RCMAIL->get_address_book($target); |
| | | |
| | | if ($TARGET && $TARGET->ready && !$TARGET->readonly) { |
| | | $arr_cids = explode(',', $cid); |
| | | if (!$TARGET || !$TARGET->ready || $TARGET->readonly) { |
| | | break; |
| | | } |
| | | |
| | | $ids = array(); |
| | | |
| | | foreach ($arr_cids as $cid) { |
| | | foreach ($cid as $cid) { |
| | | $a_record = $CONTACTS->get_record($cid, true); |
| | | |
| | | // check if contact exists, if so, we'll need it's ID |
| | |
| | | $TARGET->reset(); |
| | | $TARGET->set_group($target_group); |
| | | |
| | | if (($maxnum = $RCMAIL->config->get('max_group_members', 0)) && ($TARGET->count()->count + count($plugin['ids']) > $maxnum)) { |
| | | if ($maxnum && ($TARGET->count()->count + count($plugin['ids']) > $maxnum)) { |
| | | $OUTPUT->show_message('maxgroupmembersreached', 'warning', array('max' => $maxnum)); |
| | | $OUTPUT->send(); |
| | | } |
| | |
| | | if (($cnt = $TARGET->add_to_group($target_group, $plugin['ids'])) && $cnt > $success) |
| | | $success = $cnt; |
| | | } |
| | | else if ($plugin['result']) |
| | | else if ($plugin['result']) { |
| | | $success = $plugin['result']; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | $OUTPUT->show_message('copyerror', 'error'); |
| | | else |
| | | $OUTPUT->show_message('copysuccess', 'notice', array('nr' => $success)); |
| | | } |
| | | |
| | | // send response |
| | | $OUTPUT->send(); |
| | | |
| | |
| | | |
| | | */ |
| | | |
| | | if ($OUTPUT->ajax_call && |
| | | ($cid = get_input_value('_cid', RCUBE_INPUT_POST)) && |
| | | preg_match('/^[a-zA-Z0-9\+\/=_-]+(,[a-zA-Z0-9\+\/=_-]+)*$/', $cid) |
| | | ) { |
| | | // process ajax requests only |
| | | if (!$OUTPUT->ajax_call) |
| | | return; |
| | | |
| | | $cids = rcmail_get_cids(); |
| | | $delcnt = 0; |
| | | |
| | | foreach ($cids as $source => $cid) |
| | | { |
| | | $CONTACTS = rcmail_contact_source($source); |
| | | |
| | | if ($CONTACTS->readonly) { |
| | | // more sources? do nothing, probably we have search results from |
| | | // more than one source, some of these sources can be readonly |
| | | if (count($cids) == 1) { |
| | | $OUTPUT->show_message('contactdelerror', 'error'); |
| | | $OUTPUT->command('list_contacts'); |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | $plugin = $RCMAIL->plugins->exec_hook('contact_delete', array( |
| | | 'id' => $cid, 'source' => get_input_value('_source', RCUBE_INPUT_GPC))); |
| | | 'id' => $cid, 'source' => $source)); |
| | | |
| | | $deleted = !$plugin['abort'] ? $CONTACTS->delete($cid) : $plugin['result']; |
| | | |
| | | if (!$deleted) { |
| | | $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'contactdelerror', 'error'); |
| | | $OUTPUT->command('list_contacts'); |
| | | $OUTPUT->send(); |
| | | } |
| | | else { |
| | | $delcnt += $deleted; |
| | | } |
| | | } |
| | | |
| | | $OUTPUT->show_message('contactdeleted', 'confirmation'); |
| | | |
| | | $page = isset($_SESSION['page']) ? $_SESSION['page'] : 1; |
| | | |
| | | // update saved search after data changed |
| | | if (($search_request = $_REQUEST['_search']) && isset($_SESSION['search'][$search_request])) { |
| | | $search = (array)$_SESSION['search'][$search_request]; |
| | | $records = array(); |
| | | |
| | | // Get records from all sources (refresh search) |
| | | foreach ($search as $s => $set) { |
| | | $source = $RCMAIL->get_address_book($s); |
| | | |
| | | // reset page |
| | | $source->set_page(1); |
| | | $source->set_pagesize(9999); |
| | | $source->set_search_set($set); |
| | | |
| | | // get records |
| | | $result = $source->list_records(array('name', 'email')); |
| | | |
| | | if (!$result->count) { |
| | | unset($search[$s]); |
| | | continue; |
| | | } |
| | | |
| | | while ($row = $result->next()) { |
| | | $row['sourceid'] = $s; |
| | | $key = $row['name'] . ':' . $row['sourceid']; |
| | | $records[$key] = $row; |
| | | } |
| | | unset($result); |
| | | |
| | | $search[$s] = $source->get_search_set(); |
| | | } |
| | | |
| | | $_SESSION['search'][$search_request] = $search; |
| | | |
| | | // create resultset object |
| | | $count = count($records); |
| | | $first = ($page-1) * $CONFIG['pagesize']; |
| | | $result = new rcube_result_set($count, $first); |
| | | |
| | | // get records from the next page to add to the list |
| | | $pages = ceil((count($records) + $delcnt) / $CONFIG['pagesize']); |
| | | if ($_GET['_from'] != 'show' && $pages > 1 && $page < $pages) { |
| | | // sort the records |
| | | ksort($records, SORT_LOCALE_STRING); |
| | | |
| | | $first += $CONFIG['pagesize']; |
| | | // create resultset object |
| | | $res = new rcube_result_set($count, $first - $delcnt); |
| | | |
| | | if ($CONFIG['pagesize'] < $count) { |
| | | $records = array_slice($records, $first - $delcnt, $delcnt); |
| | | } |
| | | |
| | | $res->records = array_values($records); |
| | | $records = $res; |
| | | } |
| | | else { |
| | | unset($records); |
| | | } |
| | | } |
| | | else { |
| | | // 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(); |
| | | // get records from the next page to add to the list |
| | | $pages = ceil(($result->count + $delcnt) / $CONFIG['pagesize']); |
| | | if ($_GET['_from'] != 'show' && $pages > 1 && $page < $pages) { |
| | | $CONTACTS->set_page($page); |
| | | $records = $CONTACTS->list_records(null, -$delcnt); |
| | | } |
| | | } |
| | | |
| | | // update message count display |
| | | $OUTPUT->set_env('pagecount', ceil($result->count / $CONTACTS->page_size)); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text($result->count)); |
| | | $OUTPUT->set_env('pagecount', ceil($result->count / $CONFIG['pagesize'])); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text($result)); |
| | | |
| | | // add new rows from next page (if any) |
| | | $pages = ceil(($result->count + $deleted) / $CONTACTS->page_size); |
| | | if ($_GET['_from'] != 'show' && $pages > 1 && $CONTACTS->list_page < $pages) |
| | | rcmail_js_contacts_list($CONTACTS->list_records(null, -$deleted)); |
| | | if (!empty($records)) { |
| | | rcmail_js_contacts_list($records); |
| | | } |
| | | |
| | | // send response |
| | | $OUTPUT->send(); |
| | | } |
| | | |
| | | exit; |
| | | |
| | |
| | | |
| | | */ |
| | | |
| | | if ($RCMAIL->action == 'edit') { |
| | | // Get contact ID and source ID from request |
| | | $cids = rcmail_get_cids(); |
| | | $source = key($cids); |
| | | $cid = array_shift($cids[$source]); |
| | | |
| | | if (($cid = get_input_value('_cid', RCUBE_INPUT_GPC)) && ($record = $CONTACTS->get_record($cid, true))) |
| | | // Initialize addressbook |
| | | $CONTACTS = rcmail_contact_source($source, true); |
| | | |
| | | // Contact edit |
| | | if ($cid && ($record = $CONTACTS->get_record($cid, true))) { |
| | | $OUTPUT->set_env('cid', $record['ID']); |
| | | } |
| | | |
| | | // adding not allowed here |
| | | if ($CONTACTS->readonly) { |
| | | $OUTPUT->show_message('sourceisreadonly'); |
| | | rcmail_overwrite_action('show'); |
| | | return; |
| | | } |
| | | } |
| | | else { |
| | | $source = get_input_value('_source', RCUBE_INPUT_GPC); |
| | | |
| | | $CONTACTS = $RCMAIL->get_address_book($source); |
| | | |
| | | // find writable addressbook |
| | | if (!$CONTACTS || $CONTACTS->readonly) |
| | | $source = rcmail_default_source(true); |
| | | |
| | | // Initialize addressbook |
| | | $CONTACTS = rcmail_contact_source($source, true); |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | $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'); |
| | | $OUTPUT->add_handlers(array( |
| | | 'contactedithead' => 'rcmail_contact_edithead', |
| | | 'contacteditform' => 'rcmail_contact_editform', |
| | | 'contactphoto' => 'rcmail_contact_photo', |
| | | 'photouploadform' => 'rcmail_upload_photo_form', |
| | | )); |
| | | |
| | | if (!$CONTACTS->get_result() && $OUTPUT->template_exists('contactadd')) |
| | | if ($RCMAIL->action == 'add' && $OUTPUT->template_exists('contactadd')) |
| | | $OUTPUT->send('contactadd'); |
| | | |
| | | // this will be executed if no template for addcontact exists |
| | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2008-2011, The Roundcube Dev Team | |
| | | | Copyright (C) 2011, Kolab Systems AG | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | | PURPOSE: | |
| | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Thomas Bruederli <roundcube@gmail.com> | |
| | | | Author: Aleksander Machniak <machniak@kolabsys.com> | |
| | | +-----------------------------------------------------------------------+ |
| | | |
| | | $Id: $ |
| | | $Id$ |
| | | |
| | | */ |
| | | |
| | | // Use search result |
| | | if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) |
| | | { |
| | | $search = (array)$_SESSION['search'][$_REQUEST['_search']]; |
| | | $records = array(); |
| | | |
| | | // Get records from all sources |
| | | foreach ($search as $s => $set) { |
| | | $source = $RCMAIL->get_address_book($s); |
| | | |
| | | // reset page |
| | | $source->set_page(1); |
| | | $source->set_pagesize(99999); |
| | | $source->set_search_set($set); |
| | | |
| | | // get records |
| | | $result = $source->list_records(); |
| | | |
| | | while ($row = $result->next()) { |
| | | $row['sourceid'] = $s; |
| | | $key = $row['name'] . ':' . $row['sourceid']; |
| | | $records[$key] = $row; |
| | | } |
| | | unset($result); |
| | | } |
| | | |
| | | // sort the records |
| | | ksort($records, SORT_LOCALE_STRING); |
| | | |
| | | // create resultset object |
| | | $count = count($records); |
| | | $result = new rcube_result_set($count); |
| | | $result->records = array_values($records); |
| | | } |
| | | // selected directory/group |
| | | else { |
| | | $CONTACTS = rcmail_contact_source(null, true); |
| | | |
| | | // get contacts for this user |
| | | $CONTACTS->set_page(1); |
| | | $CONTACTS->set_pagesize(99999); |
| | | $result = $CONTACTS->list_records(null, 0, true); |
| | | } |
| | | |
| | | // send downlaod headers |
| | | send_nocacheing_headers(); |
| | |
| | | else { |
| | | $vcard = new rcube_vcard($row['vcard']); |
| | | $vcard->reset(); |
| | | |
| | | foreach ($row as $key => $values) { |
| | | list($field, $section) = explode(':', $key); |
| | | foreach ((array)$values as $value) { |
| | |
| | | } |
| | | |
| | | exit; |
| | | |
| | |
| | | |
| | | $SEARCH_MODS_DEFAULT = array('name'=>1, 'firstname'=>1, 'surname'=>1, 'email'=>1, '*'=>1); |
| | | |
| | | // select source |
| | | $source = get_input_value('_source', RCUBE_INPUT_GPC); |
| | | |
| | | if (!$RCMAIL->action && !$OUTPUT->ajax_call) { |
| | | // add list of address sources to client env |
| | | $js_list = $RCMAIL->get_address_sources(); |
| | | |
| | | // if source is not set use first directory |
| | | if (empty($source)) |
| | | $source = $js_list[key($js_list)]['id']; |
| | | |
| | | $search_mods = $RCMAIL->config->get('addressbook_search_mods', $SEARCH_MODS_DEFAULT); |
| | | $OUTPUT->set_env('search_mods', $search_mods); |
| | | $OUTPUT->set_env('address_sources', $js_list); |
| | | } |
| | | |
| | | // instantiate a contacts object according to the given source |
| | | $CONTACTS = $RCMAIL->get_address_book($source); |
| | | |
| | | $CONTACTS->set_pagesize($CONFIG['pagesize']); |
| | | |
| | | // set list properties and session vars |
| | | if (!empty($_GET['_page'])) |
| | | $CONTACTS->set_page(($_SESSION['page'] = intval($_GET['_page']))); |
| | | else |
| | | $CONTACTS->set_page(isset($_SESSION['page']) ?$_SESSION['page'] : 1); |
| | | |
| | | if (!empty($_REQUEST['_gid'])) |
| | | $CONTACTS->set_group(get_input_value('_gid', RCUBE_INPUT_GPC)); |
| | | |
| | | // set data source env |
| | | $OUTPUT->set_env('source', $source ? $source : '0'); |
| | | $OUTPUT->set_env('readonly', $CONTACTS->readonly); |
| | | if (!$OUTPUT->ajax_call) { |
| | | $search_mods = $RCMAIL->config->get('addressbook_search_mods', $SEARCH_MODS_DEFAULT); |
| | | $OUTPUT->set_env('search_mods', $search_mods); |
| | | $OUTPUT->set_pagetitle(rcube_label('addressbook')); |
| | | } |
| | | |
| | | |
| | | // general definition of contact coltypes |
| | | $CONTACT_COLTYPES = array( |
| | | 'name' => array('type' => 'text', 'size' => 40, 'limit' => 1, 'label' => rcube_label('name'), 'category' => 'main'), |
| | |
| | | // TODO: define fields for vcards like GEO, KEY |
| | | ); |
| | | |
| | | |
| | | // Addressbook UI |
| | | if (!$RCMAIL->action && !$OUTPUT->ajax_call) { |
| | | // add list of address sources to client env |
| | | $js_list = $RCMAIL->get_address_sources(); |
| | | |
| | | // use first directory by default |
| | | $source = $js_list[key($js_list)]['id']; |
| | | |
| | | // find writeable source |
| | | foreach ($js_list as $s) { |
| | | if (!$s['readonly']) { |
| | | $OUTPUT->set_env('writable_source', $s['id']); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | $search_mods = $RCMAIL->config->get('addressbook_search_mods', $SEARCH_MODS_DEFAULT); |
| | | $OUTPUT->set_env('search_mods', $search_mods); |
| | | $OUTPUT->set_env('address_sources', $js_list); |
| | | |
| | | $OUTPUT->set_pagetitle(rcube_label('addressbook')); |
| | | |
| | | $CONTACTS = rcmail_contact_source($source, true); |
| | | } |
| | | |
| | | |
| | | // instantiate a contacts object according to the given source |
| | | function rcmail_contact_source($source=null, $init_env=false) |
| | | { |
| | | global $RCMAIL, $OUTPUT, $CONFIG, $CONTACT_COLTYPES; |
| | | |
| | | if (!strlen($source)) { |
| | | $source = get_input_value('_source', RCUBE_INPUT_GPC); |
| | | } |
| | | |
| | | if (!strlen($source)) { |
| | | return null; |
| | | } |
| | | |
| | | // Get object |
| | | $CONTACTS = $RCMAIL->get_address_book($source); |
| | | $CONTACTS->set_pagesize($CONFIG['pagesize']); |
| | | |
| | | // set list properties and session vars |
| | | if (!empty($_GET['_page'])) |
| | | $CONTACTS->set_page(($_SESSION['page'] = intval($_GET['_page']))); |
| | | else |
| | | $CONTACTS->set_page(isset($_SESSION['page']) ? $_SESSION['page'] : 1); |
| | | |
| | | if (!empty($_REQUEST['_gid'])) |
| | | $CONTACTS->set_group(get_input_value('_gid', RCUBE_INPUT_GPC)); |
| | | |
| | | if (!$init_env) |
| | | return $CONTACTS; |
| | | |
| | | $OUTPUT->set_env('readonly', $CONTACTS->readonly); |
| | | $OUTPUT->set_env('source', $source); |
| | | |
| | | // reduce/extend $CONTACT_COLTYPES with specification from the current $CONTACT object |
| | | if (is_array($CONTACTS->coltypes)) { |
| | | // remove cols not listed by the backend class |
| | |
| | | } |
| | | |
| | | $OUTPUT->set_env('photocol', is_array($CONTACT_COLTYPES['photo'])); |
| | | |
| | | return $CONTACTS; |
| | | } |
| | | |
| | | |
| | | function rcmail_default_source($writable=false) |
| | | { |
| | | global $RCMAIL; |
| | | |
| | | // get list of address sources |
| | | $list = $RCMAIL->get_address_sources($writable); |
| | | |
| | | // use first directory by default |
| | | return $list[key($list)]['id']; |
| | | } |
| | | |
| | | |
| | | function rcmail_directory_list($attrib) |
| | |
| | | while ($row = $result->next()) { |
| | | $a_row_cols = array(); |
| | | |
| | | // build contact ID with source ID |
| | | if (isset($row['sourceid'])) { |
| | | $row['ID'] = $row['ID'].'-'.$row['sourceid']; |
| | | } |
| | | |
| | | // format each col |
| | | foreach ($a_show_cols as $col) |
| | | $a_row_cols[$col] = Q($row[$col]); |
| | |
| | | } |
| | | |
| | | |
| | | function rcmail_get_rowcount_text() |
| | | function rcmail_get_rowcount_text($result=null) |
| | | { |
| | | global $CONTACTS; |
| | | global $CONTACTS, $CONFIG; |
| | | |
| | | // read nr of contacts |
| | | if (!$result) { |
| | | $result = $CONTACTS->get_result(); |
| | | } |
| | | if (!$result) { |
| | | $result = $CONTACTS->count(); |
| | | } |
| | |
| | | 'name' => 'contactsfromto', |
| | | 'vars' => array( |
| | | 'from' => $result->first + 1, |
| | | 'to' => min($result->count, $result->first + $CONTACTS->page_size), |
| | | 'to' => min($result->count, $result->first + $CONFIG['pagesize']), |
| | | 'count' => $result->count) |
| | | )); |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns contact ID(s) and source(s) from GET/POST data |
| | | * |
| | | * @return array List of contact IDs per-source |
| | | */ |
| | | function rcmail_get_cids() |
| | | { |
| | | // contact ID (or comma-separated list of IDs) is provided in two |
| | | // forms. If _source is an empty string then the ID is a string |
| | | // containing contact ID and source name in form: <ID>-<SOURCE> |
| | | |
| | | $cid = get_input_value('_cid', RCUBE_INPUT_GPC); |
| | | $source = get_input_value('_source', RCUBE_INPUT_GPC); |
| | | |
| | | if (!preg_match('/^[a-zA-Z0-9\+\/=_-]+(,[a-zA-Z0-9\+\/=_-]+)*$/', $cid)) { |
| | | return array(); |
| | | } |
| | | |
| | | $cid = explode(',', $cid); |
| | | $got_source = strlen($source); |
| | | $result = array(); |
| | | |
| | | // create per-source contact IDs array |
| | | foreach ($cid as $id) { |
| | | // if _source is not specified we'll find it from decoded ID |
| | | if (!$got_source) { |
| | | list ($c, $s) = explode('-', $id, 2); |
| | | if (strlen($s)) { |
| | | $result[$s][] = $c; |
| | | } |
| | | else if (strlen($source)) { |
| | | $result[$source][] = $c; |
| | | } |
| | | } |
| | | else { |
| | | $result[$source][] = $id; |
| | | } |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | // register UI objects |
| | | $OUTPUT->add_handlers(array( |
| | | 'directorylist' => 'rcmail_directory_list', |
| | |
| | | |
| | | */ |
| | | |
| | | $source = get_input_value('_source', RCUBE_INPUT_GPC); |
| | | $CONTACTS = rcmail_contact_source($source, true); |
| | | |
| | | if ($CONTACTS->readonly || !$CONTACTS->groups) { |
| | | $OUTPUT->show_message('sourceisreadonly', 'warning'); |
| | | $OUTPUT->send(); |
| | | } |
| | | |
| | | $source = get_input_value('_source', RCUBE_INPUT_GPC); |
| | | |
| | | if ($RCMAIL->action == 'group-addmembers') { |
| | | if (($gid = get_input_value('_gid', RCUBE_INPUT_POST)) && ($ids = get_input_value('_cid', RCUBE_INPUT_POST))) { |
| | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Thomas Bruederli <roundcube@gmail.com> | |
| | | | Author: Aleksander Machniak <machniak@kolabsys.com> | |
| | | +-----------------------------------------------------------------------+ |
| | | |
| | | $Id: $ |
| | | $Id$ |
| | | |
| | | */ |
| | | |
| | |
| | | |
| | | $attrib += array('id' => "rcmImportForm"); |
| | | |
| | | $abook = new html_hiddenfield(array('name' => '_target', 'value' => $target)); |
| | | $form = $abook->show(); |
| | | $writable_books = $RCMAIL->get_address_sources(true); |
| | | |
| | | $upload = new html_inputfield(array('type' => 'file', 'name' => '_file', 'id' => 'rcmimportfile', 'size' => 40)); |
| | | $form .= html::p(null, html::label('rcmimportfile', rcube_label('importfromfile')) . html::br() . $upload->show()); |
| | | $form = html::p(null, html::label('rcmimportfile', rcube_label('importfromfile')) . $upload->show()); |
| | | |
| | | // addressbook selector |
| | | if (count($writable_books) > 1) { |
| | | $select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget')); |
| | | |
| | | foreach ($writable_books as $book) |
| | | $select->add($book['name'], $book['id']); |
| | | |
| | | $form .= html::p(null, html::label('rcmimporttarget', rcube_label('importtarget')) |
| | | . $select->show($target)); |
| | | } |
| | | else { |
| | | $abook = new html_hiddenfield(array('name' => '_target', 'value' => key($writable_books))); |
| | | $form .= $abook->show(); |
| | | } |
| | | |
| | | $check_replace = new html_checkbox(array('name' => '_replace', 'value' => 1, 'id' => 'rcmimportreplace')); |
| | | $form .= html::p(null, $check_replace->show(get_input_value('_replace', RCUBE_INPUT_GPC)) . |
| | |
| | | |
| | | */ |
| | | |
| | | // set message set for search result |
| | | // Use search result |
| | | if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) |
| | | $CONTACTS->set_search_set($_SESSION['search'][$_REQUEST['_search']]); |
| | | { |
| | | $search = (array)$_SESSION['search'][$_REQUEST['_search']]; |
| | | $records = array(); |
| | | |
| | | if (!empty($_GET['_page'])) |
| | | $page = intval($_GET['_page']); |
| | | else |
| | | $page = isset($_SESSION['page']) ? $_SESSION['page'] : 1; |
| | | |
| | | $_SESSION['page'] = $page; |
| | | |
| | | // Get records from all sources |
| | | foreach ($search as $s => $set) { |
| | | $source = $RCMAIL->get_address_book($s); |
| | | |
| | | // reset page |
| | | $source->set_page(1); |
| | | $source->set_pagesize(9999); |
| | | $source->set_search_set($set); |
| | | |
| | | // get records |
| | | $result = $source->list_records(array('name', 'email')); |
| | | |
| | | while ($row = $result->next()) { |
| | | $row['sourceid'] = $s; |
| | | $key = $row['name'] . ':' . $row['sourceid']; |
| | | $records[$key] = $row; |
| | | } |
| | | unset($result); |
| | | } |
| | | |
| | | // sort the records |
| | | ksort($records, SORT_LOCALE_STRING); |
| | | |
| | | // create resultset object |
| | | $count = count($records); |
| | | $first = ($page-1) * $CONFIG['pagesize']; |
| | | $result = new rcube_result_set($count, $first); |
| | | |
| | | // we need only records for current page |
| | | if ($CONFIG['pagesize'] < $count) { |
| | | $records = array_slice($records, $first, $CONFIG['pagesize']); |
| | | } |
| | | |
| | | $result->records = array_values($records); |
| | | } |
| | | // List selected directory |
| | | else { |
| | | $CONTACTS = rcmail_contact_source(null, true); |
| | | |
| | | // get contacts for this user |
| | | $result = $CONTACTS->list_records(array('name')); |
| | | } |
| | | |
| | | // update message count display |
| | | $OUTPUT->set_env('pagecount', ceil($result->count / $CONTACTS->page_size)); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text($rowcount)); |
| | | $OUTPUT->set_env('pagecount', ceil($result->count / $CONFIG['pagesize'])); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text($result)); |
| | | |
| | | // create javascript list |
| | | rcmail_js_contacts_list($result); |
| | | |
| | | // send response |
| | | $OUTPUT->send(); |
| | | |
| | |
| | | |
| | | */ |
| | | |
| | | $cid = get_input_value('_cid', RCUBE_INPUT_POST); |
| | | $recipients = null; |
| | | $cids = rcmail_get_cids(); |
| | | $mailto = array(); |
| | | |
| | | if ($cid && preg_match('/^[a-z0-9\+\/=_-]+(,[a-z0-9\+\/=_-]+)*$/i', $cid) && $CONTACTS->ready) |
| | | foreach ($cids as $source => $cid) |
| | | { |
| | | $CONTACTS = $RCMAIL->get_address_book($source); |
| | | |
| | | if ($CONTACTS->ready) |
| | | { |
| | | $CONTACTS->set_page(1); |
| | | $CONTACTS->set_pagesize(substr_count($cid, ',')+2); // +2 to skip counting query |
| | | $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid); |
| | | $CONTACTS->set_pagesize(count($cid) + 2); // +2 to skip counting query |
| | | $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid, false, true, true, 'email'); |
| | | |
| | | while (is_object($recipients) && ($rec = $recipients->iterate())) { |
| | | $emails = $CONTACTS->get_col_values('email', $rec, true); |
| | | $mailto[] = format_email_recipient($emails[0], $rec['name']); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | $_SESSION['mailto'][$mailto_id] = urlencode($mailto_str); |
| | | $OUTPUT->redirect(array('task' => 'mail', '_action' => 'compose', '_mailto' => $mailto_id)); |
| | | } |
| | | else |
| | | else { |
| | | $OUTPUT->show_message('nocontactsfound', 'warning'); |
| | | |
| | | } |
| | | |
| | | // send response |
| | | $OUTPUT->send(); |
| | | |
| | |
| | | |
| | | */ |
| | | |
| | | $CONTACTS = rcmail_contact_source(null, true); |
| | | $cid = get_input_value('_cid', RCUBE_INPUT_POST); |
| | | $return_action = empty($cid) ? 'add' : 'edit'; |
| | | |
| | | |
| | | // cannot edit record |
| | | if ($CONTACTS->readonly) { |
| | | $OUTPUT->show_message('contactreadonly', 'error'); |
| | |
| | | |
| | | function rcmail_contact_search() |
| | | { |
| | | global $RCMAIL, $OUTPUT, $CONTACTS, $CONTACT_COLTYPES, $SEARCH_MODS_DEFAULT; |
| | | global $RCMAIL, $OUTPUT, $CONFIG, $SEARCH_MODS_DEFAULT; |
| | | |
| | | $adv = isset($_POST['_adv']); |
| | | |
| | | // get fields/values from advanced search form |
| | | if ($adv) { |
| | | foreach ($CONTACT_COLTYPES as $col => $colprop) { |
| | | $s = trim(get_input_value('_'.$col, RCUBE_INPUT_POST, true)); |
| | | if (strlen($s)) { |
| | | foreach (array_keys($_POST) as $key) { |
| | | $s = trim(get_input_value($key, RCUBE_INPUT_POST, true)); |
| | | if (strlen($s) && preg_match('/^_search_([a-zA-Z0-9_-]+)$/', $key, $m)) { |
| | | $search[] = $s; |
| | | $fields[] = $col; |
| | | $fields[] = $m[1]; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // get sources list |
| | | $sources = $RCMAIL->get_address_sources(); |
| | | $search_set = array(); |
| | | $records = array(); |
| | | |
| | | foreach ($sources as $s) { |
| | | $source = $RCMAIL->get_address_book($s['id']); |
| | | |
| | | // check if all search fields are supported.... |
| | | if (is_array($fields)) { |
| | | $cols = $source->coltypes[0] ? array_flip($source->coltypes) : $source->coltypes; |
| | | $supported = 0; |
| | | |
| | | foreach ($fields as $f) { |
| | | if (array_key_exists($f, $cols)) { |
| | | $supported ++; |
| | | } |
| | | } |
| | | |
| | | // ...if not, we can skip this source |
| | | if ($supported < count($fields)) { |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | // reset page |
| | | $source->set_page(1); |
| | | $source->set_pagesize(9999); |
| | | |
| | | // get contacts count |
| | | $result = $source->search($fields, $search, false, false); |
| | | |
| | | if (!$result->count) { |
| | | continue; |
| | | } |
| | | |
| | | // get records |
| | | $result = $source->list_records(array('name', 'email')); |
| | | |
| | | while ($row = $result->next()) { |
| | | $row['sourceid'] = $s['id']; |
| | | $key = $row['name'] . ':' . $row['sourceid']; |
| | | $records[$key] = $row; |
| | | } |
| | | |
| | | unset($result); |
| | | $search_set[$s['id']] = $source->get_search_set(); |
| | | } |
| | | |
| | | // sort the records |
| | | ksort($records, SORT_LOCALE_STRING); |
| | | |
| | | // create resultset object |
| | | $count = count($records); |
| | | $result = new rcube_result_set($count); |
| | | |
| | | // cut first-page records |
| | | if ($CONFIG['pagesize'] < $count) { |
| | | $records = array_slice($records, 0, $CONFIG['pagesize']); |
| | | } |
| | | |
| | | $result->records = array_values($records); |
| | | |
| | | // search request ID |
| | | $search_request = md5('addr' |
| | | .(is_array($fields) ? implode($fields, ',') : $fields) |
| | | .(is_array($search) ? implode($search, ',') : $search)); |
| | | |
| | | // reset page |
| | | $CONTACTS->set_page(1); |
| | | $_SESSION['page'] = 1; |
| | | |
| | | // get contacts for this user |
| | | $result = $CONTACTS->search($fields, $search); |
| | | |
| | | // save search settings in session |
| | | $_SESSION['search'][$search_request] = $CONTACTS->get_search_set(); |
| | | $_SESSION['search'][$search_request] = $search_set; |
| | | $_SESSION['page'] = 1; |
| | | |
| | | if ($adv) |
| | | $OUTPUT->command('list_contacts_clear'); |
| | |
| | | |
| | | // update message count display |
| | | $OUTPUT->command('set_env', 'search_request', $search_request); |
| | | $OUTPUT->command('set_env', 'pagecount', ceil($result->count / $CONTACTS->page_size)); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text()); |
| | | $OUTPUT->command('set_env', 'pagecount', ceil($result->count / $CONFIG['pagesize'])); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text($result)); |
| | | |
| | | // unselect currently selected directory/group |
| | | $OUTPUT->command('unselect_directory'); |
| | | |
| | | // send response |
| | | $OUTPUT->send($adv ? 'iframe' : null); |
| | |
| | | |
| | | function rcmail_contact_search_form($attrib) |
| | | { |
| | | global $RCMAIL, $CONTACTS, $CONTACT_COLTYPES; |
| | | global $RCMAIL, $CONTACT_COLTYPES; |
| | | |
| | | $i_size = !empty($attrib['size']) ? $attrib['size'] : 30; |
| | | |
| | |
| | | ), |
| | | ); |
| | | |
| | | foreach ($CONTACT_COLTYPES as $col => $colprop) |
| | | // get supported coltypes from all address sources |
| | | $sources = $RCMAIL->get_address_sources(); |
| | | $coltypes = array(); |
| | | |
| | | foreach ($sources as $s) { |
| | | $CONTACTS = $RCMAIL->get_address_book($s['id']); |
| | | |
| | | if (is_array($CONTACTS->coltypes)) { |
| | | $contact_cols = $CONTACTS->coltypes[0] ? array_flip($CONTACTS->coltypes) : $CONTACTS->coltypes; |
| | | $coltypes = array_merge($coltypes, $contact_cols); |
| | | } |
| | | } |
| | | |
| | | // merge supported coltypes with $CONTACT_COLTYPES |
| | | foreach ($coltypes as $col => $colprop) { |
| | | $coltypes[$col] = $CONTACT_COLTYPES[$col] ? array_merge($CONTACT_COLTYPES[$col], (array)$colprop) : (array)$colprop; |
| | | } |
| | | |
| | | // build form fields list |
| | | foreach ($coltypes as $col => $colprop) |
| | | { |
| | | if ($colprop['type'] != 'image' && !$colprop['nosearch']) |
| | | { |
| | |
| | | $colprop['size'] = $i_size; |
| | | |
| | | $content = html::div('row', html::div('contactfieldlabel label', Q($label)) |
| | | . html::div('contactfieldcontent', rcmail_get_edit_field($col, '', $colprop, $ftype))); |
| | | . html::div('contactfieldcontent', rcmail_get_edit_field('search_'.$col, '', $colprop, $ftype))); |
| | | |
| | | $form[$category]['content'][] = $content; |
| | | } |
| | | } |
| | | |
| | | $hiddenfields = new html_hiddenfield(array( |
| | | 'name' => '_source', 'value' => get_input_value('_source', RCUBE_INPUT_GPC))); |
| | | $hiddenfields->add(array('name' => '_gid', 'value' => $CONTACTS->group_id)); |
| | | $hiddenfields = new html_hiddenfield(); |
| | | $hiddenfields->add(array('name' => '_adv', 'value' => 1)); |
| | | |
| | | $out = $RCMAIL->output->request_form(array( |
| | |
| | | |
| | | */ |
| | | |
| | | // Get contact ID and source ID from request |
| | | $cids = rcmail_get_cids(); |
| | | $source = key($cids); |
| | | $cid = array_shift($cids[$source]); |
| | | |
| | | // Initialize addressbook source |
| | | $CONTACTS = rcmail_contact_source($source, true); |
| | | |
| | | // read contact record |
| | | if (($cid = get_input_value('_cid', RCUBE_INPUT_GPC)) && ($record = $CONTACTS->get_record($cid, true))) { |
| | | if ($cid && ($record = $CONTACTS->get_record($cid, true))) { |
| | | $OUTPUT->set_env('cid', $record['ID']); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | //$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->add_handlers(array( |
| | | 'contacthead' => 'rcmail_contact_head', |
| | | 'contactdetails' => 'rcmail_contact_details', |
| | | 'contactphoto' => 'rcmail_contact_photo', |
| | | )); |
| | | |
| | | $OUTPUT->send('contact'); |