| +-----------------------------------------------------------------------+ */ $SEARCH_MODS_DEFAULT = array('name'=>1, 'firstname'=>1, 'surname'=>1, 'email'=>1, '*'=>1); // general definition of contact coltypes $CONTACT_COLTYPES = array( 'name' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('name'), 'category' => 'main'), 'firstname' => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('firstname'), 'category' => 'main'), 'surname' => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('surname'), 'category' => 'main'), 'email' => array('type' => 'text', 'size' => 40, 'maxlength' => 254, 'label' => $RCMAIL->gettext('email'), 'subtypes' => array('home','work','other'), 'category' => 'main'), 'middlename' => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('middlename'), 'category' => 'main'), 'prefix' => array('type' => 'text', 'size' => 8, 'maxlength' => 20, 'limit' => 1, 'label' => $RCMAIL->gettext('nameprefix'), 'category' => 'main'), 'suffix' => array('type' => 'text', 'size' => 8, 'maxlength' => 20, 'limit' => 1, 'label' => $RCMAIL->gettext('namesuffix'), 'category' => 'main'), 'nickname' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('nickname'), 'category' => 'main'), 'jobtitle' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('jobtitle'), 'category' => 'main'), 'organization' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('organization'), 'category' => 'main'), 'department' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('department'), 'category' => 'main'), 'gender' => array('type' => 'select', 'limit' => 1, 'label' => $RCMAIL->gettext('gender'), 'options' => array('male' => $RCMAIL->gettext('male'), 'female' => $RCMAIL->gettext('female')), 'category' => 'personal'), 'maidenname' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('maidenname'), 'category' => 'personal'), 'phone' => array('type' => 'text', 'size' => 40, 'maxlength' => 20, 'label' => $RCMAIL->gettext('phone'), 'subtypes' => array('home','home2','work','work2','mobile','main','homefax','workfax','car','pager','video','assistant','other'), 'category' => 'main'), 'address' => array('type' => 'composite', 'label' => $RCMAIL->gettext('address'), 'subtypes' => array('home','work','other'), 'childs' => array( 'street' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('street'), 'category' => 'main'), 'locality' => array('type' => 'text', 'size' => 28, 'maxlength' => 50, 'label' => $RCMAIL->gettext('locality'), 'category' => 'main'), 'zipcode' => array('type' => 'text', 'size' => 8, 'maxlength' => 15, 'label' => $RCMAIL->gettext('zipcode'), 'category' => 'main'), 'region' => array('type' => 'text', 'size' => 12, 'maxlength' => 50, 'label' => $RCMAIL->gettext('region'), 'category' => 'main'), 'country' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('country'), 'category' => 'main'), ), 'category' => 'main'), 'birthday' => array('type' => 'date', 'size' => 12, 'maxlength' => 16, 'label' => $RCMAIL->gettext('birthday'), 'limit' => 1, 'render_func' => 'rcmail_format_date_col', 'category' => 'personal'), 'anniversary' => array('type' => 'date', 'size' => 12, 'maxlength' => 16, 'label' => $RCMAIL->gettext('anniversary'), 'limit' => 1, 'render_func' => 'rcmail_format_date_col', 'category' => 'personal'), 'website' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('website'), 'subtypes' => array('homepage','work','blog','profile','other'), 'category' => 'main'), 'im' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => $RCMAIL->gettext('instantmessenger'), 'subtypes' => array('aim','icq','msn','yahoo','jabber','skype','other'), 'category' => 'main'), 'notes' => array('type' => 'textarea', 'size' => 40, 'rows' => 15, 'maxlength' => 500, 'label' => $RCMAIL->gettext('notes'), 'limit' => 1), 'photo' => array('type' => 'image', 'limit' => 1, 'category' => 'main'), 'assistant' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('assistant'), 'category' => 'personal'), 'manager' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('manager'), 'category' => 'personal'), 'spouse' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => $RCMAIL->gettext('spouse'), 'category' => 'personal'), // TODO: define fields for vcards like GEO, KEY ); $PAGE_SIZE = $RCMAIL->config->get('addressbook_pagesize', $RCMAIL->config->get('pagesize', 50)); // Addressbook UI if (!$RCMAIL->action && !$OUTPUT->ajax_call) { // add list of address sources to client env $js_list = $RCMAIL->get_address_sources(); // count all/writeable sources $writeable = 0; $count = 0; foreach ($js_list as $sid => $s) { $count++; if (!$s['readonly']) { $writeable++; } // unset hidden sources if ($s['hidden']) { unset($js_list[$sid]); } } $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_env('writable_source', $writeable); $OUTPUT->set_pagetitle($RCMAIL->gettext('contacts')); $_SESSION['addressbooks_count'] = $count; $_SESSION['addressbooks_count_writeable'] = $writeable; // select address book $source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC); // use first directory by default if (!strlen($source) || !isset($js_list[$source])) { $source = $RCMAIL->config->get('default_addressbook'); if (!strlen($source) || !isset($js_list[$source])) { $source = strval(key($js_list)); } } $CONTACTS = rcmail_contact_source($source, true); } // remove undo information... if ($undo = $_SESSION['contact_undo']) { // ...after timeout $undo_time = $RCMAIL->config->get('undo_timeout', 0); if ($undo['ts'] < time() - $undo_time) $RCMAIL->session->remove('contact_undo'); } // register UI objects $OUTPUT->add_handlers(array( 'directorylist' => 'rcmail_directory_list', 'savedsearchlist' => 'rcmail_savedsearch_list', 'addresslist' => 'rcmail_contacts_list', 'addresslisttitle' => 'rcmail_contacts_list_title', 'addressframe' => 'rcmail_contact_frame', 'recordscountdisplay' => 'rcmail_rowcount_display', 'searchform' => array($OUTPUT, 'search_form') )); // register action aliases $RCMAIL->register_action_map(array( 'add' => 'edit.inc', 'group-create' => 'groups.inc', 'group-rename' => 'groups.inc', 'group-delete' => 'groups.inc', 'group-addmembers' => 'groups.inc', 'group-delmembers' => 'groups.inc', 'search-create' => 'search.inc', 'search-delete' => 'search.inc', )); // instantiate a contacts object according to the given source function rcmail_contact_source($source=null, $init_env=false, $writable=false) { global $RCMAIL, $OUTPUT, $CONTACT_COLTYPES, $PAGE_SIZE; if (!strlen($source)) { $source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC); } // Get object $CONTACTS = $RCMAIL->get_address_book($source, $writable); $CONTACTS->set_pagesize($PAGE_SIZE); // 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 ($group = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_GP)) { $CONTACTS->set_group($group); } if (!$init_env) { return $CONTACTS; } $OUTPUT->set_env('readonly', $CONTACTS->readonly); $OUTPUT->set_env('source', (string) $source); $OUTPUT->set_env('group', $group); // 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) { if (is_array($colprop['childs'])) { foreach ($colprop['childs'] as $childcol => $childprop) $colprop['childs'][$childcol] = array_merge((array)$CONTACT_COLTYPES[$col]['childs'][$childcol], $childprop); } $CONTACT_COLTYPES[$col] = $CONTACT_COLTYPES[$col] ? array_merge($CONTACT_COLTYPES[$col], $colprop) : $colprop; } } } $OUTPUT->set_env('photocol', is_array($CONTACT_COLTYPES['photo'])); return $CONTACTS; } function rcmail_set_sourcename($abook) { global $OUTPUT, $RCMAIL; // get address book name (for display) if ($abook && $_SESSION['addressbooks_count'] > 1) { $name = $abook->get_name(); if (!$name) { $name = $RCMAIL->gettext('personaladrbook'); } $OUTPUT->set_env('sourcename', html_entity_decode($name, ENT_COMPAT, 'UTF-8')); } } function rcmail_directory_list($attrib) { global $RCMAIL, $OUTPUT; if (!$attrib['id']) $attrib['id'] = 'rcmdirectorylist'; $out = ''; $jsdata = array(); $line_templ = html::tag('li', array( 'id' => 'rcmli%s', 'class' => '%s', 'noclose' => true), html::a(array('href' => '%s', 'rel' => '%s', 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('list','%s',this)"), '%s')); $sources = (array) $OUTPUT->get_env('address_sources'); reset($sources); // currently selected source $current = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC); foreach ($sources as $j => $source) { $id = strval(strlen($source['id']) ? $source['id'] : $j); $js_id = rcube::JQ($id); // set class name(s) $class_name = 'addressbook'; if ($current === $id) $class_name .= ' selected'; if ($source['readonly']) $class_name .= ' readonly'; if ($source['class_name']) $class_name .= ' ' . $source['class_name']; $name = $source['name'] ?: $id; $out .= sprintf($line_templ, rcube_utils::html_identifier($id, true), $class_name, rcube::Q($RCMAIL->url(array('_source' => $id))), $source['id'], $js_id, $name); $groupdata = array('out' => $out, 'jsdata' => $jsdata, 'source' => $id); if ($source['groups']) $groupdata = rcmail_contact_groups($groupdata); $jsdata = $groupdata['jsdata']; $out = $groupdata['out']; $out .= ''; } $OUTPUT->set_env('contactgroups', $jsdata); $OUTPUT->set_env('collapsed_abooks', (string)$RCMAIL->config->get('collapsed_abooks','')); $OUTPUT->add_gui_object('folderlist', $attrib['id']); $OUTPUT->include_script('treelist.js'); // add some labels to client $OUTPUT->add_label('deletegroupconfirm', 'groupdeleting', 'addingmember', 'removingmember', 'newgroup', 'grouprename', 'searchsave', 'namex', 'save' ); return html::tag('ul', $attrib, $out, html::$common_attrib); } function rcmail_savedsearch_list($attrib) { global $RCMAIL, $OUTPUT; if (!$attrib['id']) $attrib['id'] = 'rcmsavedsearchlist'; $out = ''; $line_templ = html::tag('li', array( 'id' => 'rcmli%s', 'class' => '%s'), html::a(array('href' => '#', 'rel' => 'S%s', 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('listsearch', '%s', this)"), '%s')); // Saved searches $sources = $RCMAIL->user->list_searches(rcube_user::SEARCH_ADDRESSBOOK); foreach ($sources as $source) { $id = $source['id']; $js_id = rcube::JQ($id); // set class name(s) $classes = array('contactsearch'); if (!empty($source['class_name'])) $classes[] = $source['class_name']; $out .= sprintf($line_templ, rcube_utils::html_identifier('S'.$id, true), join(' ', $classes), $id, $js_id, rcube::Q($source['name'] ?: $id) ); } $OUTPUT->add_gui_object('savedsearchlist', $attrib['id']); return html::tag('ul', $attrib, $out, html::$common_attrib); } function rcmail_contact_groups($args) { global $RCMAIL; $groups_html = ''; $groups = $RCMAIL->get_address_book($args['source'])->list_groups(); if (!empty($groups)) { $line_templ = html::tag('li', array( 'id' => 'rcmli%s', 'class' => 'contactgroup'), html::a(array('href' => '#', 'rel' => '%s:%s', 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('listgroup',{'source':'%s','id':'%s'},this)"), '%s')); // append collapse/expand toggle and open a new