ldap_addressbook-master/ldap_addressbook.module
ldap_addressbook.module
<?php //Dear emacs, please make this buffer -*- php -*- /** * @file * A module for drupal to maintain an addressbook with LDAP as backend. * * Copyright (C) 2005 Ola Thoresen * Copyright (C) 2006 Andre dos Anjos * * This file is part of the ldap_addresbook module for Drupal. * * The ldap_addressbook module is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA **/ /** * @todo Ideas to be implemented (difficulty from 1 to 5, being 5 the * hardest): * * # Import and export to LDIF format (you will have to write a set of * functions to do that [difficulty 4]; * * # Import entries from other addressbooks according to a filter. [difficulty * 4]; * * # Implement configurable renaming of LDAP fields by the user with i18n * translation possible [difficulty 3]; * * # Make sure all strings can be translated by the means of the t() function * [difficulty 1]; * * # Trust garbage collection to be executed by cron() instead of by your * functions [difficult 1, just requires extensive testing]. * * # Place a "contact" entry under the "create content" menu so the whole * addressbook seems integrated within drupal [difficulty 4]; * * # Integrated the Adressbook Search into drupal's search facility * [difficulty 5]; **/ require_once("LDAPDirectory.inc"); require_once("Format.inc"); /** * Implementation of hook_help(). * * I should probably write some more helpful info here * **/ function ldap_addressbook_help($section) { switch ($section) { case 'admin/modules#description': return t('An addressbook with a LDAP based backend'); } } /** * Implementation of hook_perm(). * * This is the thinking behind permissions for this module: * # Users that can change the LDAP server settings and know its passwords * should get the "Administer" permission; * # Users that can edit and change the entries in the addressbook should get * the "Edit" permission. Please note that users that can administer the LDAP * server settings will naturally get permission to edit the LDAP server, but * <b>not</b> the contrary. * # Users that can only view the addressbook entries, should get the "Search" * permission. Please note that users that have either the "Edit" permission * or the "Administer" permission should automatically gain "Search" * permissions. **/ function ldap_addressbook_perm() { return array('Administer LDAP addressbook module', 'Edit LDAP addressbook', 'Search LDAP addressbook', 'Have private LDAP addressbook'); } /** * A helper to determine how to compute the permissions for a given user. * * @param $op The operation to be performed. Possible values: "admin", "edit", * "search", which match the hook_perm() above. **/ function _ldap_addressbook_allow($op='search') { //The permission logic $can_admin = user_access('Administer LDAP addressbook module'); if ($op == 'admin') return $can_admin; $can_edit = $can_admin || user_access('Edit LDAP addressbook'); if ($op == 'edit') return $can_edit; if ($op == 'search') return $can_edit || user_access('Search LDAP addressbook'); //if you get here, I'm sorry, you don't have any permission to do anything //else! Print something! drupal_set_message ('Calling _ldap_addressbook_allow($op='.$op.') is strange!', error); return FALSE; } /** * Implementation of hook_menu(). **/ function ldap_addressbook_menu($may_cache) { $dir = new DrupalDirectory(); $items = array(); if ($may_cache) { // $may_cache is normally set when there are changes in the page that need // refreshing the menus. An example is when you change the themes of a // page or logout/login. In any other cases, these entries are saved on // the DB(?) and then used without reading this code. If you don't like // this behavior, move these lines to the else{} clause bellow. // To test that this is called with a theme change or upon logout/login, // uncomment the line bellow. //trigger_error('hook_menu() called with $may_cache = TRUE!'); $items[] = array('path' => $dir->module_name() . '/new', 'title' => t('new contact'), 'callback' => '_menu_ldap_addressbook_new', 'access' => _ldap_addressbook_allow('edit'), 'type' => MENU_CALLBACK, 'weight' => 5); $items[] = array('path' => $dir->module_name() . '/search', 'title' => t('search addressbook'), 'callback' => '_menu_ldap_addressbook_search', 'access' => _ldap_addressbook_allow('search'), 'type' => MENU_CALLBACK); } else { // This is the default callback, that launches the tabbed view. No // arguments required, just the function that gets the first argument // and tries to view the LDAP entry. This item is uncacheable since it // might change quite dynamically. $top_title = t('view'); if (arg(2)) $top_title = t('Contact ').arg(3).t(' (at ').arg(2).t(' addressbook)'); $items[] = array('path' => $dir->module_name().'/node', 'title' => $top_title, 'callback' => '_menu_ldap_addressbook_view', 'access' => _ldap_addressbook_allow('search'), 'type' => MENU_CALLBACK); $items[] = array('path' => 'admin/settings/'.$dir->module_name(), 'title' => t('ldap_addressbook'), 'callback' => '_lab_settings', 'access' => _ldap_addressbook_allow('admin'), 'type' => MENU_NORMAL_ITEM); if (arg(2)) { // This is used if you click in the 'view' tab on the // 'view/edit/delete' contact display. It is the first to pop up // (default tab) and stays to the left of the tabbed panel. This item // is uncacheable since it might change quite dynamically. $items[] = array('path' => $dir->module_name().'/node/'.arg(2).'/'.arg(3).'/view', 'title' => t('view'), 'callback' => '_menu_ldap_addressbook_view', 'access' => _ldap_addressbook_allow('search'), 'type' => MENU_LOCAL_TASK, 'weight' => -10); // This is used if you click in the 'edit' tab on the // 'view/edit/delete' contact display. It is the second to pop up and // stays in the middle of the tabbed panel. This item is uncacheable // since it might change quite dynamically. $items[] = array('path' => $dir->module_name().'/node/'.arg(2).'/'.arg(3).'/edit', 'title' => t('edit'), 'callback' => '_menu_ldap_addressbook_edit', 'access' => _ldap_addressbook_allow('edit'), 'type' => MENU_LOCAL_TASK, 'weight' => -5); // This is used if you click in the 'delete' tab on the // 'view/edit/delete' contact display. It is the third to pop up and // stays to the right of the tabbed panel. This item is uncacheable // since it might change quite dynamically. $items[] = array('path' => $dir->module_name().'/node/'.arg(2).'/'.arg(3).'/delete', 'title' => t('delete'), 'callback' => '_menu_ldap_addressbook_delete', 'access' => _ldap_addressbook_allow('edit'), 'type' => MENU_LOCAL_TASK, 'weight' => 0); } } return $items; } /** * Implementation of hook_settings() in an specialized way to be able to catch * the password validation correctly. * * This hook sets-up a form for the user to fill in the default properties of * the LDAP server and the user accounts needed to connect to the addressbook. **/ function _lab_settings() { if (!_ldap_addressbook_allow('admin')) drupal_access_denied(); $dir = new DrupalDirectory(); $form = array(); /** * SERVER SETTINGS */ $form['server'] = array('#type' => 'fieldset', '#title' => t('Server settings'), '#collapsible' => TRUE, '#collapsed' => TRUE); $form['server']['ldap_addressbook_host'] = array('#type' => 'textfield', '#title' => t('Host'), '#default_value' => $dir->host, '#required' => TRUE, '#size' => 30, '#maxlength' => 128, '#description' => t('The name of the host running the LDAP server.')); $form['server']['ldap_addressbook_port'] = array('#type' => 'textfield', '#title' => t('Port'), '#default_value' => $dir->port, '#required' => TRUE, '#size' => 5, '#maxlength' => 10, '#description' => t('The TCP to use for the server')); $options = array('2' => t('Version 2'), '3' => t('Version 3')); $form['server']['ldap_addressbook_version'] = array('#type' => 'select', '#title' => t('LDAP version'), '#default_value' => $dir->proto, '#options' => $options, '#description' => t('The LDAP protocol version to use.')); // $hash_options = array('clear' => t('clear text'), // 'crypt' => t('crypt'), // 'sha' => t('sha'), // 'ssha' => t('ssha'), // 'md5' => t('md5'), // 'smd5' => t('smd5')); // $form['server']['ldap_addressbook_password_hash'] = // array('#type' => 'select', // '#title' => t('LDAP password hashing'), // '#default_value' => $dir->password_hash(), // '#options' => $hash_options, // '#description' => t('Defines the hash algorithm to be used when storing the passwords on the drupal database. This will <b>not</b> prevent the passwords to be transmitted from your web browser to the server running drupal in clear-text, but after that, all transactions involving the password (namely the connection to the LDAP server) will go on encrypted.')); $form['server']['ldap_addressbook_tmp'] = array('#type' => 'textfield', '#title' => t('Temporary directory'), '#default_value' => $dir->tmp_path(), '#required' => TRUE, '#size' => 60, '#maxlength' => 128, '#after_build' => array('system_check_directory'), '#description' => t('The name of a temporary directory, <b>relative to you drupal installation</b>, where I\'ll temporarily store user jpeg files (a.k.a avatars), if necessary. It is not necessary <b>not</b> to prepend or append slashes (/).')); /** * ADDRESSBOOK SETTINGS */ $form['addressbook'] = array('#type' => 'fieldset', '#title' => t('Addressbook settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => t('These settings control the location and access of the information inside the server.')); $form['addressbook']['ldap_addressbook_base'] = array('#type' => 'textfield', '#title' => t('DN of the addressbook'), '#default_value' => $dir->dir, '#required' => TRUE, '#size' => 60, '#maxlength' => 128, '#description' => t('The base distinguished name of the addressbook')); $ldap_user = $dir->user(); $form['addressbook']['ldap_addressbook_user'] = array('#type' => 'textfield', '#title' => t('DN of an authenticated LDAP user'), '#default_value' => $ldap_user->dn, '#required' => TRUE, '#size' => 60, '#maxlength' => 128, '#description' => t('User distinguished name (DN) with read and write access to the addressbook DN')); $form['addressbook']['user_pass1'] = array('#type' => 'password', '#default_value' => '', '#size' => 15, '#maxlength' => 30, '#prefix' => '<div class="container-inline">', '#title' => t('User password')); $form['addressbook']['user_pass2'] = array('#type' => 'password', '#default_value' => '', '#size' => 15, '#maxlength' => 30, '#suffix' => '</div>', '#description' => t('Fill in both fields. A blank value does <b>not</b> reset the password.')); $form['addressbook']['user_passwd_reset'] = array('#type' => 'checkbox', '#default_value' => 0, '#title' => t('User password reset'), '#description' => t('Check it to erase the password from the database.')); $form['addressbook']['ldap_addressbook_anonymous'] = array('#type' => 'checkbox', '#title' => t('Bind anonymously for read-only operations'), '#default_value' => $dir->read_anonymously(), '#description' => t('If I should try to bind anomymously for read-only operations, check this box. The authenticated user will <b>not</b> be used in this case.')); $form['addressbook']['ldap_addressbook_private_template'] = array('#type' => 'textfield', '#title' => 'User (private) addressbook', '#default_value' => $dir->userbook_template(), '#size' => 60, '#maxlength' => 128, '#description' => t('If the users are allowed to have private addressbooks they can input data that other users cannot see, specify the template string of the DN for these private addressbooks here. The \'%s\' string will be substitued by the user name.')); /** * FORMAT SETTINGS */ $form['format'] = array('#type' => 'fieldset', '#title' => t('Formatting settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => t('These settings control how your contacts are displayed when you conduct searches or specific entry displays.')); $form['format']['ldap_addressbook_fields'] = array('#type' => 'textfield', '#title' => t('Fields of interest'), '#default_value' => implode(' ', $dir->fields()), '#required' => TRUE, '#size' => 80, '#maxlength' => 256, '#description' => t('The list of fields of importance in this addressbook. The individual elements should be separated by <b>spaces</b>. These are the elements that the module will allow you to set or unset in your addressbook.')); $form['format']['ldap_addressbook_summary'] = array('#type' => 'textfield', '#title' => t('Fields for summaries'), '#default_value' => implode(' ', $dir->summary_fields()), '#required' => TRUE, '#size' => 80, '#maxlength' => 256, '#description' => t('The list of fields you want to see on directory summaries where multiple entries are shown at the same time. The individual elements should be separated by <b>spaces</b>. The common use of these fields is when displaying search results with more than 1 entry.')); $form['format']['ldap_addressbook_jpeg_size'] = array('#type' => 'textfield', '#title' => t('Maximum photo size'), '#default_value' => $dir->maximum_jpeg_size(), '#size' => 10, '#maxlength' => 16, '#description' => t('The maximum geometrical size (in pixels) for the jpeg file to be used for user pictures (avatar) in the LDAP addressbook. Larger photos will be rescaled to this value. Smaller photos will be expanded to this size, proportionally.')); $form['submit'] = array('#type' => 'submit', '#value' => t('Save configuration')); $form['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults')); return drupal_get_form('_lab_settings', $form); } /** * Validates the administrative settings. * * @param $form_id This form identifier * @param $form_values The values collected on the form */ function _lab_settings_validate($form_id, $form_values) { if ($form_values['user_pass1'] != $form_values['user_pass2']) { form_set_error('user_pass1', 'Passwords for the read/write user do not match!'); form_set_error('user_pass2'); } // else if (!empty($form_values['user_pass1'])) { // //test the hashing // $hash = _lab_hash($form_values['user_pass1'], // $form_values['ldap_addressbook_password_hash']); // if (!$hash) form_set_error('ldap_addressbook_password_hash'); // } //implement host checking? } /** * Submits the administrative settings. * * @param $form_id This form identifier * @param $form_values The values collected on the form */ function _lab_settings_submit($form_id, $form_values) { if (!_ldap_addressbook_allow('admin')) drupal_access_denied(); if ($_POST['op'] == t('Save configuration')) { $dir = new DrupalDirectory(); //takes care of most entries in one shot foreach ($form_values as $k => $v) { if (strpos($k, $dir->module_name()) === 0) variable_set($k, $v); } //now let's see the password fields if ($form_values['user_passwd_reset']) { drupal_set_message(t('Reseting read-write user password')); variable_del('ldap_addressbook_user_pass'); } if (!empty($form_values['user_pass1'])) variable_set('ldap_addressbook_user_pass', $form_values['user_pass1']); drupal_set_message(t('The configuration options have been saved.')); } else if ($_POST['op'] == t('Reset to defaults')) { $dir = new DrupalDirectory(); //takes care of most entries in one shot foreach ($form_values as $k => $v) if (strpos($k, $dir->module_name()) === 0) variable_del($k); variable_del('ldap_addressbook_user_pass'); drupal_set_message(t('The configuration options have been reset to their default values.')); } else { drupal_set_message(t('I do not recognize operation '.$_POST['op']), 'error'); drupal_set_message(t('The settings have not been saved because of the errors.'), 'error'); return; } return; } /** * Implementation of hook_block(). * * A simple block that will allow you to search the addressbook * **/ function ldap_addressbook_block($op = 'list', $delta = 0) { if ($op == 'list') { $block[0]['info'] = t('Search LDAP addressbook'); return $block; } else { if (($op == 'view') && _ldap_addressbook_allow('search')) { switch ($delta) { case 0: $block['subject'] = t('addressbook'); $form = array(); $form['ldap_search_string'] = array('#type' => 'textfield', '#title' => '', '#default_value' => "", '#size' => 18, '#maxlength' => 128); $form[] = array('#type' => 'submit', '#value' => t('Search')); $form[] = array('#type' => 'submit', '#value' => t('Create')); $block['content'] = drupal_get_form ('_ldap_addressbook_block_search', $form); return $block; } } } return; } /** * What to do when the user clicks the submission button **/ function _ldap_addressbook_block_search_submit($form_id, $form_values) { $dir = new DrupalDirectory(); if ($_POST['op'] == t('Search')) { drupal_goto($dir->module_name().'/search/all/'. $form_values['ldap_search_string']); } else if ($_POST['op'] == t('Create')) { drupal_goto($dir->module_name().'/new'); } } /** * Remove old jpeg photos in a drupal-visible temporary directory. This cannot * be `/tmp' unless that is mapped to the web server. **/ function _ldap_addressbook_remove_garbage() { $dir = new DrupalDirectory(); $glob= $dir->tmp_path().'/'.$dir->module_name().'*'; foreach (glob($glob) as $filename) unlink($filename); } /* * Prints, in an orderly and standardized fashion, the results of a query to * the addressbook. This function is called when the user calls the module root * ('ldap_addressbook') or when executing a query in the form of * ('ldap_addressbook/search/...'). The extra parameters are passed to this * function. * * @param $privacy The default is to search globally. If this variable is set * to either private or global than the search will only happen on that * scope. * @param $what The search term * @param $sort The sorting criteria for the results * * @see DrupalDirectory::search() **/ function _menu_ldap_addressbook_search ($privacy="all", $what='*', $sort='cn') { if (!_ldap_addressbook_allow('search')) { drupal_access_denied(); return; } if ($privacy == 'private' && !user_access('Have private LDAP addressbook')) { drupal_access_denied(); return; } if ($privacy != 'private' && $privacy != 'global' && $privacy != 'all') { drupal_access_denied(); return; } //@todo remove this call //do the garbage collection first. This might become a problem since we //could be removing images from other users, but... _ldap_addressbook_remove_garbage(); $dir = new DrupalDirectory(); $output = ''; //if there was something posted, that has preference over the parameters if (isset($_POST['edit']) && isset($_POST['edit']['ldap_search_string']) && ! empty($_POST['edit']['ldap_search_string'])) $what = $_POST['ldap_search_string']; if ($what != '*') { $output .= t("Searching for") . " $what...<br />"; //compose a search filter that searches through all relevant fields //configured. $filter = '(|'; foreach ($dir->fields() as $field) $filter .= "($field=*$what*)"; $filter .= ')'; } else { $output .= t("Displaying all entries...<br />"); $filter = ""; } $info = $dir->search($filter, array($sort), $dir->summary_fields(), $privacy); if (count($info['global']) == 0 && count($info['private']) == 0) $output = t("Searching $privacy addressbook(s) has found no matching entries found for key `$what'."); else if (count($info['global']) == 1 && count($info['private']) == 0) { //redirect to view page! drupal_goto($dir->module_name().'/node/global/'.$info['global'][0]["cn"][0].'/view'); } else if (count($info['global']) == 0 && count($info['private']) == 1) { //redirect to view page! drupal_goto($dir->module_name().'/node/private/'.$info['private'][0]["cn"][0].'/view'); } else { //count is >= 1 for both if (count($info['private']) > 0) { $output .= '<h2>Private addressbook contacts</h2>'; $output .= _lab_multi_view($info['private'], $dir->summary_fields(), $dir->module_name(), $dir->tmp_path(), _ldap_addressbook_allow('edit'), 'private'); } if (count($info['global']) > 0) { $output .= '<h2>Global addressbook contacts</h2>'; $output .= _lab_multi_view($info['global'], $dir->summary_fields(), $dir->module_name(), $dir->tmp_path(), _ldap_addressbook_allow('edit'), 'global'); } } return $output; } /** * Present a form for which the user can create a new entry in the LDAP * addressbook. **/ function _menu_ldap_addressbook_new() { if (!_ldap_addressbook_allow('edit')) drupal_access_denied(); $dir = new DrupalDirectory(); $form = array('#type' => 'fieldset', '#title' => t('new contact'), '#collapsible' => FALSE); //All fields are automatically written, except the name fields since this //will compose the CN entry for this new contact. $form['givenname'] = array('#type' => 'textfield', '#title' => _lat('givenname'), '#size' => 40, '#maxlength' => 128, '#required' => TRUE); $form['sn'] = array('#type' => 'textfield', '#title' => _lat('sn'), '#size' => 40, '#maxlength' => 128, '#required' => TRUE); $special = array('givenname', 'sn', 'jpegphoto', 'cn'); foreach ($dir->fields() as $field) { $lfield = strtolower($field); if (in_array($field, $special)) continue; $form["$field"] = array('#type' => 'textfield', '#title' => _lat($field), '#size' => 60, '#maxlength' => 128); } if (in_array('jpegphoto', $dir->fields())) { $form['jpegphoto'] = array('#type' => 'file', '#title' => _lat('jpegphoto')); } if ($dir->private_book()) { $form['private'] = array('#type' => 'checkbox', '#title' => t('On private addressbook'), '#description' => t('Check this box to include this new entry in your private addressbook instead of the global one.')); } $form[] = array('#type' => 'submit', '#value' => t('Create new contact')); //this function call also defines the official name of this form return drupal_get_form('_ldap_addressbook_new', $form); } /** * Validates the new LDAP addressbook entry * * @param $form_id The identifier for this form * @param $form_values The values set by the user **/ function _ldap_addressbook_new_validate($form_id, $form_values) { if ($form_values['givenname'] == '') { form_set_error('givenname', t('You must set the first name of the new contact.')); } if ($form_values['sn'] == '') { form_set_error('sn', t('You must set the last name of the new contact.')); } } /** * Submits the new LDAP addressbook entry (after validation). * * @param $form_id The identifier for this form * @param $form_values The values set by the user **/ function _ldap_addressbook_new_submit($form_id, $form_values) { //@todo Remove this call from here. Already have cron job... //do the garbage collection first. This might become a problem since we //could be removing images from other users, but... _ldap_addressbook_remove_garbage(); $dir = new DrupalDirectory(); foreach ($form_values as $k => $v) { //just to avoid extra form fields... if (!in_array($k, $dir->fields()) or $k == '0') continue; if ($k != 'jpegphoto' and empty($v)) continue; //check for jpeg photos, rescale and set if ($k == 'jpegphoto') { if (count($_FILES) != 0) { $jpeg = _ldap_addressbook_jpeg_stream(); if (!empty($jpeg)) $info['jpegPhoto'] = $jpeg; } } else $info[$k] = $v; } //checks the privacy $privacy = 'global'; if (in_array('private', array_keys($form_values)) && $form_values['private']) { $privacy = 'private'; } if (!$dir->add($info, $privacy)) drupal_goto($dir->module_name()."/new"); else { $cn = $info['givenname'].' '.$info['sn']; drupal_set_message(t("Successfuly added LDAP addressbook entry $cn")); drupal_goto($dir->module_name()."/node/$privacy/$cn/view"); } return; } /** * Present a form for which the user can delete an existing entry in the LDAP * addressbook. If this function is called without any parameters, a listing * with all entries should be presented, together with check boxes for * deleting entries. * * @param $privacy The addressbook at which this entry is. Can be 'private' or * 'global' and is obligatory. * @param $cn The unique common name of the entry you want to delete **/ function _menu_ldap_addressbook_delete($privacy=NULL, $cn=NULL) { if (!_ldap_addressbook_allow('edit')) { drupal_access_denied(); return; } //make sure we are not getting called via a tab entry if (arg(2)) $privacy=arg(2); if (arg(3)) $cn=arg(3); if (!$privacy) { drupal_set_message(t('I cannot edit a node without knowing the addressbook you are refering to. Use "global" or "private" as qualifiers to your query. Redirecting to search...'), 'error'); drupal_goto($dir->module_name().'/search'); } if ($privacy == 'private' && !user_access('Have private LDAP addressbook')) { drupal_access_denied(); return; } if ($privacy != 'global' && $privacy != 'private') { drupal_access_denied(); return; } if (!$cn) { drupal_set_message(t("No name was given as parameter, redirecting to $privacy search..."), 'error'); drupal_goto($dir->module_name()."/search/$privacy"); } $dir = new DrupalDirectory(); $info = $dir->get_one($privacy, $cn); if (!$info) { drupal_set_message('Invalid CN parameter, redirecting to search...'); drupal_goto($dir->module_name()."/search/$privacy"); } //All fields are automatically written, except the name fields since this //will compose the CN entry for this new contact. $output = ''; if(array_key_exists('jpegphoto', $info)) { $name_entry = array('data' => '<h2>'.$cn.'</h2>'); $imagefilename = _lab_rescale($info['jpegphoto'][0], 50, $tmp_path, $path); if (!$imagefilename) { $output .= '[Corrupted image]'; } else { $output .= theme_image($imagefilename, '['.$cn.'\'s photo]', '['.$cn.'\'s photo]'); } } $output .= '<h2>Confirm deletion of contact '.$info['cn'][0].'?</h2><br/>'; $form = array('#type' => 'fieldset', '#title' => t('Confirm LDAP contact deletion?'), '#collapsible' => FALSE); $form['cn'] = array('#type' => 'hidden', '#value' => $info['cn'][0]); $form['privacy'] = array('#type' => 'hidden', '#value' => $privacy); $form[] = array('#type' => 'submit', '#value' => t('Delete contact')); //this function call also defines the official name of this form $output .= drupal_get_form('_ldap_addressbook_delete', $form); return $output; } /** * Submits the new LDAP addressbook entry (after validation) * * @param $form_id The identifier for this form * @param $form_values The values set by the user **/ function _ldap_addressbook_delete_submit($form_id, $form_values) { $dir = new DrupalDirectory(); $cn = $form_values['cn']; $privacy = $form_values['privacy']; if (!$dir->delete($cn, $privacy)) { drupal_set_message(t('I could not delete the LDAP addressbook entry `'. $cn."'"), 'error'); drupal_goto("ldap_addressbook/node/$privacy/$cn/view"); } else { drupal_set_message(t('Successfuly deleted LDAP addressbook entry `'. $cn."'")); drupal_goto('ldap_addressbook/search/all/'.$cn); } return; } /** * Presents a form for which the user can edit an existing entry in the LDAP * addressbook, based on the cn attribute given as parameter * * @param $privacy The addressbook where the entry to be edited is. Can take * two values: 'global' or 'private'. * @param $cn The unique common name of the entry you want to delete **/ function _menu_ldap_addressbook_edit($privacy=NULL, $cn=NULL) { if (!_ldap_addressbook_allow('edit')) { drupal_access_denied(); return; } //make sure we are not getting called via a tab entry if (arg(2)) $privacy=arg(2); if (arg(3)) $cn=arg(3); if (!$privacy) { drupal_set_message(t('I cannot edit a node without knowing the addressbook you are refering to. Use "global" or "private" as qualifiers to your query. Redirecting to search...'), 'error'); drupal_goto($dir->module_name().'/search/global'); } if ($privacy == 'private' && !user_access('Have private LDAP addressbook')) { drupal_access_denied(); return; } if ($privacy != 'global' && $privacy != 'private') { drupal_access_denied(); return; } if (!$cn) { drupal_set_message(t('No name was given as parameter, redirecting to search...'), 'error'); drupal_goto($dir->module_name()."/search/$privacy"); } $dir = new DrupalDirectory(); $info = $dir->get_one($privacy, $cn); if (!info) { drupal_set_message(t("Cannot find a <b>single</b> entry matching '$cn'"), 'error'); return; } //All fields are automatically written, except the name fields since this //will compose the CN entry for this new contact. $form['#attributes'] = array('enctype' => 'multipart/form-data'); $form['cn'] = array('#type' => hidden, '#value' => $info['cn'][0]); $form['givenname'] = array('#type' => 'textfield', '#title' => _lat('givenname'), '#default_value' => $info['givenname'][0], '#size' => 40, '#maxlength' => 128); $form['sn'] = array('#type' => 'textfield', '#title' => _lat('sn'), '#default_value' => $info['sn'][0], '#size' => 40, '#maxlength' => 128); $special = array('givenname', 'sn', 'jpegphoto', 'cn'); foreach ($dir->fields() as $field) { $lfield = strtolower($field); if (in_array($field, $special)) continue; $default = ''; if (array_key_exists($field, $info)) $default = $info[$field][0]; if (array_key_exists($lfield, $info)) $default = $info[$lfield][0]; $form["$field"] = array('#type' => 'textfield', '#title' => _lat($field), '#default_value' => $default, '#size' => 60, '#maxlength' => 128); } if (in_array('jpegphoto', $dir->fields())) { if (!empty($info['jpegphoto'][0])) { $imagefilename = _lab_rescale($info['jpegphoto'][0], 50, $dir->tmp_path(), $dir->module_name()); $form['old_image'] = array('#value' => theme_image($imagefilename, t("$cn's photo"), t("$cn's photo"))); $form['jpegphoto_reset'] = array('#type' => 'checkbox', '#title' => t('Remove this photo from the addressbook'), '#default_value' => 0); } $form['jpegphoto'] = array('#type' => 'file', '#title' => _lat('jpegphoto')); } $form[] = array('#type' => 'submit', '#value' => t('Submit changes')); //this function call also defines the official name of this form return drupal_get_form('_ldap_addressbook_edit', $form); } /** * Validates the new LDAP addressbook entry * * @param $form_id The identifier for this form * @param $form_values The values set by the user **/ function _ldap_addressbook_edit_validate($form_id, $form_values) { if ($form_values['givenname'] == '') { form_set_error('', t('You must set the first name of the new contact.')); } if ($form_values['sn'] == '') { form_set_error('', t('You must set the last name of the new contact.')); } } /** * Implements the hook_cron(). **/ function ldap_addressbook_cron() { //do the garbage collection first. This might become a problem since we //could be removing images from other users, but... _ldap_addressbook_remove_garbage(); } /** * Prepares a stream to upload a jpeg into the LDAP server * * @param $field The name of the form field that contained the entry for the * file. **/ function _ldap_addressbook_jpeg_stream ($field='edit') { $dir = new DrupalDirectory(); $upfile = current($_FILES[$field]['tmp_name']); $jpeg_to_ldap = _lab_rescale_file($upfile, $dir->maximum_jpeg_size(), $dir->tmp_path(), $dir->module_name()); if (!$jpeg_to_ldap) return FALSE; //trigger_error('jpeg was rescaled and sits at '.$jpeg_to_ldap); unlink($upfile); //delete old upload $jpeg_file = fopen($jpeg_to_ldap, 'rb'); $jpeg_stream = fread($jpeg_file, filesize($jpeg_to_ldap)); fclose($jpeg_file); unlink($jpeg_to_ldap); //delete rescaled jpeg return $jpeg_stream; } /** * Submits the new LDAP addressbook entry (after validation) * * @param $form_id The identifier for this form * @param $form_values The values set by the user **/ function _ldap_addressbook_edit_submit($form_id, $form_values) { $dir = new DrupalDirectory(); $cn = $form_values['cn']; $newcn = $form_values['givenname'].' '.$form_values['sn']; $info = $dir->get_one($cn); //pre-populate //just to safe guard us if (!isset($form_values['jpegphoto_reset'])) $form_values['jpegphoto_reset'] = 0; foreach ($form_values as $k => $v) { //just to avoid extra form fields... if ((! in_array($k, $dir->fields())) or $k == '0') continue; if ($k != 'jpegphoto') { if (empty($v)) $info[$k] = array(); else $info[$k] = $v; } else { if (count($_FILES) != 0 && !$form_values['jpegphoto_reset']) { $jpeg = _ldap_addressbook_jpeg_stream(); if (!empty($jpeg)) $info['jpegphoto'] = $jpeg; } } } //check the jpeg photo reset if ($form_values['jpegphoto_reset']) $info['jpegphoto'] = array(); //unset the object class unset($info['objectclass']); if (!$dir->modify($info)) drupal_goto($dir->module_name()."/node/$cn/edit"); drupal_goto($dir->module_name()."/node/$newcn/view"); } /** * Present a table at which the user can view an existing entry in the LDAP * addressbook, based on the cn attribute given as parameter * * @param $privacy The default is to search globally. If this variable is set * to either private or global than the search will only happen on that * scope. * @param $cn The unique common name of the entry you want to delete **/ function _menu_ldap_addressbook_view($privacy=NULL, $cn=NULL) { if (!_ldap_addressbook_allow('search')) { drupal_access_denied(); return; } //@todo Remove this call //do the garbage collection first. This might become a problem since we //could be removing images from other users, but... _ldap_addressbook_remove_garbage(); //make sure we are not getting called via a tab entry if (arg(2)) $privacy=arg(2); if (arg(3)) $cn=arg(3); if (!$privacy) { drupal_set_message(t('I cannot display a node without knowing the addressbook you are refering to. Use "global" or "private" as qualifiers to your query. Redirecting to search...'), 'error'); drupal_goto($dir->module_name().'/search/global'); } if ($privacy == 'private' && !user_access('Have private LDAP addressbook')) { drupal_access_denied(); return; } if ($privacy != 'global' && $privacy != 'private') { drupal_access_denied(); return; } if (!$cn) { drupal_set_message(t('No name was given as parameter, redirecting to search...'), 'error'); drupal_goto($dir->module_name()."/search/$privacy"); } $dir = new DrupalDirectory(); $info = $dir->get_one($privacy, $cn); if (! $info) { drupal_set_message(t("No entry with CN=$cn was found in $privacy context")); drupal_goto(''); } return _lab_view($info, $dir->fields(), $dir->module_name(), $dir->tmp_path()); } ?>