<?php
/**
 * Horde Hooks configuration file.
 *
 * THE HOOKS PROVIDED IN THIS FILE ARE EXAMPLES ONLY.  DO NOT ENABLE THEM
 * BLINDLY IF YOU DO NOT KNOW WHAT YOU ARE DOING.  YOU HAVE TO CUSTOMIZE THEM
 * TO MATCH YOUR SPECIFIC NEEDS AND SYSTEM ENVIRONMENT.
 *
 * This file is where you define any hooks, for preferences or general Horde
 * use, that your installation uses. The functions in this file can vastly
 * change how your installation behaves, so make sure to test out any changes
 * here before doing them in a production environment.
 *
 * Hook function names are automatically determined. The format of the name
 * is:
 *
 * _<type of hook>_hook_<name of hook>.
 *
 * Types of hooks that are defined in this file are 'prefs' (hooks to set the
 * value of preferences), 'horde' (hooks for the Horde Framework scripts) and
 * 'app' (where app is any Horde application name, like 'imp') hooks that are
 * application specific.
 *
 * So, a hook to set the preference 'theme' would be named
 * "_prefs_hook_theme".
 *
 * NOTE 1: Having a hook function in this file does NOT mean that the hook
 * will automatically be used. YOU MUST enable the hook. For preferences, set
 * 'hook' => true in that preferences attributes; for other hooks, there will
 * be a configuration option in each application's conf.php file such as
 * $conf['hooks']['hookname'] which must be set to true.
 *
 * NOTE 2: Preferences hooks are ONLY executed on login. Preferences are
 * cached during a users session and, to avoid unnecessary overhead every time
 * a preference is accessed, the results of hooks are cached as well. This
 * leads to ...
 *
 * NOTE 3: Any preference that is NOT LOCKED, that is set by a hook, WILL BE
 * SAVED WITH THAT VALUE. This means several things:
 * 1) Users will get the results of the hook set for them in their
 *    preferences.
 * 2) By virtue of this, the next time they log in and load their
 *    preferences, the hook will NOT be called, because in their last session,
 *    we saved the results of the hook for them. However, if the preference is
 *    locked, the result of the hook will never be saved.
 *
 * $Horde: horde/config/hooks.php.dist,v 1.73.6.19 2009/08/13 15:43:56 jan Exp $
 */

// Example theme hook function. This shows how you can access things like the
// currently logged in user, global variables, server config, etc. It isn't,
// however, something you probably want to actually use in production, by
// virtue of demonstrating all those. :)

// if (!function_exists('_prefs_hook_theme')) {
//     function _prefs_hook_theme($username = null)
//     {
//         if (Auth::getAuth() != 'chuck') {
//             return 'mozilla';
//         }
//
//         global $registry;
//         switch ($registry->getApp()) {
//         case 'imp':
//             return 'brown';
//
//         case 'turba':
//             return 'orange';
//
//         case 'kronolith':
//             return 'green';
//
//         default:
//             return '';
//         }
//     }
// }

// Example preferences change hook. Preferences change hooks are named
// _prefs_change_hook_<prefname>, and are called with no arguments
// when a preference is changed to a new value (re-setting it to the
// same value will not trigger a call).

// if (!function_exists('_prefs_change_hook_theme')) {
//     function _prefs_change_hook_theme()
//     {
//         $GLOBALS['notification']->push('You changed your theme to ' . $GLOBALS['prefs']->getValue('theme') . '!');
//     }
// }

// Example from_addr hook function. THIS FUNCTION ASSUMES THAT YOU ARE USING
// AN LDAP SERVER and that your /etc/ldap.conf or wherever it is correctly set
// to a valid host.
//
// You get passed NOTHING; you are responsible for bringing in to scope any
// information you need. You can "global" anything else you need. Return an
// address - either just the user@ side or a full address - and it will be
// used.
//
// If you want to use this code you will need to uncomment it below.

// if (!function_exists('_prefs_hook_from_addr')) {
//     function _prefs_hook_from_addr($name = null)
//     {
//         if (is_null($name)) {
//             $name = Auth::getAuth();
//         }
//         if (!empty($name)) {
//             $base_context = 'o=myorg';
//             $scope = 'sub';
//
//             // You will probably need to replace cd= with uid=; this
//             // syntax is for Netware 5.1 nldap.
//             $cmd  = '/usr/bin/ldapsearch -b ' . $base_context . ' -s ' . $scope . ' cn=';
//             $cmd .= escapeShellCmd(Auth::getAuth());
//             $cmd .= ' | /usr/bin/grep mail | /usr/bin/awk \'{print $2}\'';
//             $mails = `$cmd`;
//             $mail_array = explode("\n", $mails);
//
//             // Send back the first email found, not the whole list.
//             $mail = $mail_array['0'];
//
//             // If no email address is found, then the login name will
//             // be used.
//             return (empty($mail) ? '' : $mail);
//         }
//
//         return '';
//     }
// }

// Here is another way of doing the same thing.

// if (!function_exists('_prefs_hook_from_addr')) {
//     function _prefs_hook_from_addr($user = null)
//     {
//         $ldapServer = '172.31.0.236';
//         $ldapPort = '389';
//         $searchBase = 'o=myorg';
//
//         $ds = @ldap_connect($ldapServer, $ldapPort);
//
//         if (is_null($user)) {
//             $user = Auth::getAuth();
//             if ($user === false) {
//                 return '';
//             }
//         }
//
//         // You will probably need to replace cn= with uid=; this
//         // syntax is for Netware 5.1 nldap.
//         $searchResult = @ldap_search($ds, $searchBase, 'cn=' . $user);
//         $information = @ldap_get_entries($ds, $searchResult);
//         if ($information === false || $information['count'] == 0) {
//             $name = '';
//         } else {
//             if ($information[0]['mail'][0] != '') {
//                 $name = $information[0]['mail'][0];
//             } else {
//                 $name = $information[0]['cn'][0];
//             }
//         }
//
//         ldap_close($ds);
//
//         return (empty($name) ? $user : $name);
//     }
// }

// Here is an example fullname hook function to set the fullname from the GECOS
// information in the passwd file.

// if (!function_exists('_prefs_hook_fullname')) {
//     function _prefs_hook_fullname($user = null)
//     {
//         if (is_null($user)) {
//             $user = Auth::getBareAuth();
//             if ($user === false) {
//                 return '';
//             }
//         }
//         $array = posix_getpwnam($user);
//         $gecos_array = explode(',', $array['gecos']);
//         return (empty($gecos_array) ? $user : $gecos_array[0]);
//     }
// }

// This is another example of how to get the user's full name, in this case
// from an ldap server. In this example we look if a Spanish name exists and
// return this or the standard 'cn' entry if not.

// if (!function_exists('_prefs_hook_fullname')) {
//     function _prefs_hook_fullname($user = null)
//     {
//         $ldapServer = 'ldap.example.com';
//         $ldapPort = '389';
//         $searchBase = 'ou=people,o=example.com';
//         $ldapcharset = 'utf-8';
//         $outputcharset = NLS::getCharset();
//
//         $ds = @ldap_connect($ldapServer, $ldapPort);
//
//         if (is_null($user)) {
//             $user = Auth::getAuth();
//             if ($user === false) {
//                 return '';
//             }
//         }
//         $searchResult = @ldap_search($ds, $searchBase, 'uid=' . $user);
//         $information = @ldap_get_entries($ds, $searchResult);
//         if ($information === false || $information['count'] == 0) {
//             $name = '';
//         } else {
//             if ($information[0]['cn;lang-es'][0] != '') {
//                 $name = $information[0]['cn;lang-es'][0];
//             } else {
//                 $name = $information[0]['cn'][0];
//             }
//         }
//
//         ldap_close($ds);
//
//         $name = String::convertCharset($name, $ldapcharset, $outputcharset);
//         return (empty($name) ? $user : $name);
//     }
// }

// IE on Mac hangs when there are several icons to be loaded. At least on some
// systems. This hook disables the show_icons preference from Krononlith for
// these browsers.

// if (!function_exists('_prefs_hook_show_icons')) {
//     function _prefs_hook_show_icons()
//     {
//         global $browser;
//         if ($browser->getPlatform() == 'mac' &&
//             $browser->getBrowser() == 'msie') {
//             return false;
//         } else {
//             return true;
//         }
//     }
// }

// This hook is called when a user submits a signup request.  It allows
// a chance to alter or validate the data submitted by a user before any
// attempts are made to add them to the system.

// if (!function_exists('_horde_hook_signup_preprocess')) {
//     function _horde_hook_signup_preprocess($info) {
//         $info['user_name'] = String::lower($info['user_name']);
//         return $info;
//     }
// }

// This hook is called when a signup is queued for administrative approval.
// This example sends a notification message to the web server
// administrator's e-mail address.

// if (!function_exists('_horde_hook_signup_queued')) {
//     function _horde_hook_signup_queued_walkdata($fields, $data)
//     {
//         $msg = '';
//         foreach ($data as $field => $value) {
//             if ($field == 'password' || $field == 'url') {
//                 continue;
//             }
//
//             if (is_array($value)) {
//                 $msg .= _horde_hook_signup_queued_walkdata($fields, $value);
//             } else {
//                 $field = isset($fields[$field]['label']) ?
//                          $fields[$field]['label'] : $field;
//                 $msg .= "$field: $value\n";
//             }
//         }
//         return $msg;
//     }
//
//     function _horde_hook_signup_queued($userID, $data)
//     {
//         require_once 'Mail.php';
//         global $conf, $registry;
//
//         $headers = array(
//             'To'      => $_SERVER['SERVER_ADMIN'],
//             'From'    => $_SERVER['SERVER_ADMIN'],
//             'Subject' => 'New ' . $registry->get('name', 'horde') . ' Signup'
//         );
//
//         $extraFields = Horde::callHook('_horde_hook_signup_getextra');
//
//         $msg  = _("A new signup has been received and is awaiting your approval.");
//         $msg .= "\n\n";
//         $msg .= _horde_hook_signup_queued_walkdata($extraFields, $data);
//         $msg .= "\n";
//         $msg .= sprintf(_("You can approve this signup at %s"), Horde::applicationUrl('admin/user.php', true, -1));
//
//         $mailer = Mail::factory($conf['mailer']['type'], $conf['mailer']['params']);
//         return $mailer->send($_SERVER['SERVER_ADMIN'], $headers, $msg);
//     }
// }

// Here is an example _horde_hook_signup_getextra function. It returns any
// extra fields which need to be filled in when a non registered user wishes
// to sign up.
// The example here takes the hypothetical case where we would want to store
// extra information about a user into a turba sql address book. All this
// function does then is to include the attributes.php file from the turba
// config directory and return the $attributes array.
// Otherwise any structure that would return an array with the following
// syntax would be valid:
//   $somearray['somefieldname'] = array(...
//      label    - the text that the user will see attached to this field
//      type     - any allowed Horde_Form field type
//      params   - any allowed parameter to Horde_Form field types
//      required - boolean, true or false whether this field is mandatory
//      readonly - boolean, true or false whether this editable
//      desc     - any help text attached to the field
// NOTE: You DO NEED Turba to be correctly installed before you can use this
// example below.

// if (!function_exists('_horde_hook_signup_getextra')) {
//     function _horde_hook_signup_getextra()
//     {
//         global $registry;
//         require $registry->get('fileroot', 'turba') . '/config/attributes.php';
//         return $attributes;
//     }
// }

// Following on from the example in the above function, this is how a sample
// _horde_hook_signup_addextra function would look like.
// Here we connect to the database using the sql parameters configured in
// $conf and store the extra fields in turba_objects, using the $userId as the
// key for the object and values from the $extra array.
// You could create your own sql syntax or code to store this in whichever
// backend you require.
// NOTE: You DO NEED Turba to be correctly installed before you can use this
// example below. It also assumes that you are using an SQL backend.

// if (!function_exists('_horde_hook_signup_addextra')) {
//     function _horde_hook_signup_addextra($userID, $extra, $password)
//     {
//         global $conf;
//
//         require_once 'DB.php';
//         $_db = &DB::connect($conf['sql'], true);
//
//         $fields = array();
//         $values = array();
//         foreach ($extra as $field => $value) {
//             $fields[] = 'object_' . String::lower($field);
//             $values[] = $_db->quote(String::convertCharset($value, NLS::getCharset(), $conf['sql']['charset']));
//         }
//         $fields[] = 'object_id';
//         $values[] = $_db->quote($userID);
//
//         $query  = 'INSERT INTO turba_objects ( owner_id, ' . implode(', ', $fields) . ')';
//         $query .= ' VALUES ( \'admin\', ' . implode(', ', $values) . ')';
//         $result = $_db->query($query);
//
//         return is_a($result, 'PEAR_Error') ? $result : true;
//     }
// }

// Here is an example _horde_hook_preauthenticate that make Horde respect the
// Unix convention of not allowing login when a file named /etc/nologin exist.
// This function get passed the username, credential and realm information but
// they are not used in this example.

// if (!function_exists('_horde_hook_preauthenticate')) {
//     function _horde_hook_preauthenticate($userID, $credential, $realm)
//     {
//         return !file_exists('/etc/nologin');
//     }
// }

// Here is an example of validating the user's right to login to Horde by
// consulting group membership in an LDAP directory.  That way, if your Horde
// installation is configured to authenticate against IMP which in turn
// authenticate via IMAP, it is still possible to limit access to Horde by
// group membership.  The following example had been made with an MS Active
// Directory in mind.  Note that if the LDAP directory is unavailable or some
// other error occur, authentication will fail.

// if (!function_exists('_horde_hook_postauthenticate')) {
//     function _horde_hook_postauthenticate($userID, $credential, $realm)
//     {
//         $ldapServer = 'ad.example.com';
//         $ldapPort = '389';
//         // Note that credential is sent plain-text in this case, so don't use
//         // privileged account here or setup SSL (by using port 636 above).
//         $binddn = 'cn=WithoutPrivilege,dc=ulaval-dev,dc=ca';
//         $bindpw = 'Remember this is sent in the clear unless SSL is used';
//         $searchBase = 'ou=People,dc=example,dc=com';
//         // Attribute to match $userID against in search
//         $userAttr = 'sAMAccountName';
//         // Group membership attribute, need to be all lowercase
//         $groupAttr = 'memberof';
//         // Attribute to check for right to use Horde
//         $groupdn = 'cn=HordeUser,ou=People,dc=example,dc=com';
//         $ret = true;
//
//         $ds = @ldap_connect($ldapServer, $ldapPort);
//
//         if (@ldap_bind($ds, $binddn, $bindpw)) {
//             $searchResult = @ldap_search($ds, $searchBase, $userAttr . '=' . $userID, array($groupAttr), 0, 1, 5);
//             if ($information = @ldap_get_entries($ds, $searchResult)) {
//                 // make pattern case-insensitive
//                 $pattern = '/' . $groupdn . '/i';
//                 foreach ($information[0][$groupAttr] as $group) {
//                     if (preg_match($pattern, $group)) {
//                         $ret = true;
//                         break;
//                     }
//                 }
//             }
//         }
//
//         ldap_close($ds);
//         return $ret;
//     }
// }

// Here is an example of creating credentials needed by the LDAP Auth driver
// for adding/deleting/updating users.

// if (!function_exists('_horde_hook_authldap')) {
//     function _horde_hook_authldap($userID, $credentials = null)
//     {
//         $entry['dn'] = 'uid=' . $userID . ',ou=People,dc=example.com';
//         if (isset($credentials) && isset($credentials['user_fullname'])) {
//             $entry['cn'] = $credentials['user_fullname'];
//         } else {
//             $entry['cn'] = $userID;
//         }
//         $entry['sn'] = $userID;
//         $entry['objectclass'][0] = 'top';
//         $entry['objectclass'][1] = 'person';
//         $entry['objectclass'][2] = 'qmailuser';
//         $entry['objectclass'][3] = 'CourierMailACcount';
//         $entry['mailhost'] = 'mail.example.com';
//         $entry['mailMessageStore'] = '/home/mail/' . $userID;
//         $entry['homeDirectory'] = '/home/mail/' . $userID;
//         $entry['mailbox'] = $entry['homeDirectory'] . '/Maildir';
//         $entry['uid'] = $userID;
//         $entry['accountStatus'] = 'active';
//         $entry['mailQuota'] = '104857600S';
//         $entry['mail'] = $userID;
//         $entry['uidNumber'] = 501;
//         $entry['gidNumber'] = 501;
//
//         // need to check for new users (password) and edited users (user_pass_2)
//         if (isset($credentials) && isset($credentials['password'])) {
//             $entry['userPassword'] =  '{MD5}' . base64_encode(pack('H*', md5($credentials['password'])));
//         } elseif (isset($credentials) && isset($credentials['user_pass_2'])) {
//             $entry['userPassword'] =  '{MD5}' . base64_encode(pack('H*', md5($credentials['user_pass_2'])));
//         }
//         $entry['deliveryMode'] = 'nolocal';
//         return $entry;
//     }
// }

// This example is of a function that can be called when a share listing is
// requested. It takes a userid, a permissions level, an optional string
// containing a userid to restrict the owner of the shares returned, and the
// result of the corresponding Horde_Share::listShares() call as its
// parameters. As is the case in the previous three functions, if a PEAR_Error
// result is returned the Horde_Share::listShares() call that triggered this
// hook will fail with the returned result.

// if (!function_exists('_horde_hook_share_list')) {
//     function _horde_hook_share_list($userid, $perm, $owner, &$share_list)
//     {
//         global $registry;
//         //error_log('Number of ' . $GLOBALS['registry']->getApp() . ' shares' . ($owner ?
//         //    ' owned by ' . $owner : '') . ' available to ' . $userid . ' at perms level ' .
//         //    $perm . ': ' .  count($share_list));
//         return true;
//     }
// }

// Here is an example _username_hook_frombackend function. It appends the
// virtual domain to the user name.
//
// ex. $HTTP_HOST = 'mail.mydomain.com', $userID = 'myname' returns:
//   'myname@mydomain.com'

// if (!function_exists('_username_hook_frombackend')) {
//     function _username_hook_frombackend($userID)
//     {
//         $vdomain = getenv('HTTP_HOST');
//         $vdomain = preg_replace('|^mail\.|i', '', $vdomain);
//         $vdomain = String::lower($vdomain);
//
//         return $userID . '@' . $vdomain;
//     }
// }

// Here is an example _username_hook_tobackend function as a counterpart of the
// previous example. It strips the virtual domain from the user name.
//
// ex. $HTTP_HOST = 'mail.mydomain.com', $userID = 'myname' returns:
//   'myname@mydomain.com'

// if (!function_exists('_username_hook_tobackend')) {
//     function _username_hook_tobackend($userID)
//     {
//         $vdomain = getenv('HTTP_HOST');
//         $vdomain = preg_replace('|^mail\.|i', '', $vdomain);
//         $vdomain = '@' . String::lower($vdomain);
//
//         if (substr($userID, -strlen($vdomain)) == $vdomain) {
//             $userID = substr($userID, 0, -strlen($vdomain));
//         }
//
//         return $userID;
//     }
// }

// Here is an example _username_hook_frombackend function. It converts the user
// name to all lower case. This might be necessary if an authentication backend
// is case insensitive to take into account that Horde's preference system is
// case sensitive.
//
// ex. $userID = 'MyName' returns: 'myname'

// if (!function_exists('_username_hook_frombackend')) {
//     function _username_hook_frombackend($userID)
//     {
//         return String::lower($userID);
//     }
// }

// Here is an example _perms_hook_denied function.  It is called if a user
// tries to make an action that is under permission control and that he
// doesn't have sufficient permissions for.  It can be used to show the user a
// custom message including HTML code (you have to take care about HTML
// escaping on your own), or to interrupt the code flow and send the user to a
// different page for example.

// if (!function_exists('_perms_hook_denied')) {
//     function _perms_hook_denied($permission)
//     {
//         if (($pos = strpos($permission, ':')) === false) {
//             $app = $permission;
//         } else {
//             $app = substr($permission, 0, $pos);
//         }
//
//         return sprintf('Permission denied. Click <a href="http://www.example.com/upgrade.php?app=%s">HERE</a> to upgrade %s.',
//                        $app, $GLOBALS['registry']->get('name'));
//     }
// }

// This is an example of a group hook.  To use it you must set the group
// driver to hooks in conf.php.  You can add users to groups as normal, and
// in addition this function will be called to dynamically include users in
// the group.  Note the group hook interface changed as of Horde 3.2.
// In this example we will look up whether or not this user is part of the
// "IT_department" group using an external database.

// if (!function_exists('_group_hook')) {
//     function _group_hook($groupName, $userName)
//     {
//         global $conf;
//
//         switch ($groupName) {
//         case 'IT_department':
//             $dept = 'IT';
//             include_once 'DB.php';
//             $_db = &DB::connect($conf['sql'], true);
//             $query = 'SELECT COUNT(*) FROM departments WHERE user_name = ? AND department = ?';
//             $values = array($userName, $dept);
//             $result = $_db->getOne($query, $values);
//             return (!is_a($result, 'PEAR_Error') && $result > 0);
//
//         default:
//             return false;
//         }
//     }
// }

// You can keep your existing Horde <= 3.1 group hook functions and use
// this group hook function to link them to the Horde 3.2 interface.

// if (!function_exists('_group_hook')) {
//     function _group_hook($groupName, $userName)
//     {
//         if (function_exists('_group_hook_' . str_replace(':', '__', $groupName))) {
//             return call_user_func('_group_hook_' . str_replace(':', '__', $groupName));
//         }
//     }
// }

// This is an example of a post-push hook; it is called right after an
// application is pushed successfully onto the app stack.

// if (!function_exists('_horde_hook_post_pushapp')) {
//     function _horde_hook_post_pushapp($app)
//     {
//         if ($app == 'imp') {
//             // Run some code if the app is switched to imp
//         }
//     }
// }

// IMSP share hooks.  These require at least Turba 2.2 and Horde 3.2
/*if (!empty($GLOBALS['conf']['imsp']['enabled'])) {
    require_once 'Net/IMSP/Utils.php';
    if (!function_exists('_horde_hook_share_init')) {
        function _horde_hook_share_init(&$share_obj, $app)
        {
            // cfgSources won't be defined here before Turba 2.2
            if (($app == 'turba') && (!empty($GLOBALS['cfgSources'])) &&
                (!empty($GLOBALS['cfgSources']['imsp']['use_shares']))) {

                // Only do this once per session or when this session variable
                // is purposely unset.
                if (!empty($_SESSION['imsp_synched'])) {
                    return;
                }
                $results = Net_IMSP_Utils::synchShares($share_obj, $GLOBALS['cfgSources']['imsp']);
                if (!is_a($results, 'PEAR_Error')) {
                    $_SESSION['imsp_synched'] = true;

                    // Now deal with adding or removing address books from prefs.
                    // FIXME: Updating prefs seems to hang the server. Narrowed
                    // down to the fact that prefs->setValue() also attempts to call
                    // a hook. (Commenting out the callHook call fixes). Can
                    // anyone verify this on their install?
                    $dirty = false;
                    $abooks = $GLOBALS['prefs']->getValue('addressbooks');
                    if (!empty($abooks)) {
                        $abooks = explode("\n", $GLOBALS['prefs']->getValue('addressbooks'));
                    } else {
                        $abooks = array();
                    }

                    if (count($results['removed'] > 0)) {
                        foreach ($results['removed'] as $sharename) {
                           $key = array_search($sharename, $abooks);
                           if ($key === true) {
                               unset($abooks[$key]);
                               $dirty = true;
                           }
                        }
                    }
                    if (count($results['added']) > 0) {
                        foreach ($results['added'] as $sharename) {
                            if (array_search($sharename, $abooks) === false) {
                                $abooks[] = $sharename;
                                $dirty = true;
                            }
                        }
                    }
                    if ($dirty) {
                        $result = $GLOBALS['prefs']->setValue('addressbooks', implode("\n", $abooks));
                    }

                    // We have to save the connection info for the imsp server since
                    // the share_modify hook will not occur from within turba's context.
                    $_SESSION['imsp_config'] = $GLOBALS['cfgSources']['imsp']['params'];
                }
            }
        }

        function _horde_hook_share_modify(&$share)
        {
            $params = unserialize($share->get('params'));
            if (is_array($params) && !empty($params['source']) &&
                $params['source'] = 'imsp' &&
                !empty($_SESSION['imsp_config'])) {

                // Ensure we don't try to change ownership.
                $params = @unserialize($share->get('params'));
                $bookName = $params['name'];
                if (strpos($bookName, $share->get('owner')) !== 0) {
                    $err = &PEAR::raiseError('Changing ownership of IMSP address books is not supported.');
                    $GLOBALS['notification']->push($err);
                    return $err;
                }


                //Update the ACLS
                $perms = $share->getPermission();
                $users = $perms->getUserPermissions();
                foreach ($users as $user => $perm) {
                    $acl = Net_IMSP_Utils::permsToACL($perm);
                    $result = Net_IMSP_Utils::setACL($_SESSION['imsp_config'],
                                           $bookName,
                                           $user, $acl);

                }
            }
        }
    }
}*/
