6.0.0-git
2024-03-28

Diff for CustomizingPreferencesH3 between 28 and 29

[[toc]]

+ User Contributed Preferences

Perhaps the greatest feature of Horde and all of it's modules is the flexibility to adapt to a myriad of different uses and I would expect that eventually, a more integrated system of managing 'defaults' will become part of the code but at this moment in time, the only way to effect settings system wide is to edit the various prefs.php file inside each module.

I thought it would be interesting to share what people do to the various preferences and it would make a handy reference to point people towards if they ask on the various lists.

The methodology of capturing some of these 'strings' of values is that I usually create the setup exactly how I want it for my  'Administrator' user and then copy the values out of the SQL database and paste them into the appropriate spot in the prefs.php file.

-----

+++ hooks.phpDefault Identity

++++ LDAP
I have created some hooks for capturing the users Identity and Email address to automatically set their Default identity the  first time that they log in. These hooks assume LDAP backend and should be instructive for someone wanting to create their own custom hooks...this wasn't easy to figure out.

The first modification I did to hooks.php was to add the following (don't forget to add the {{'hook' => 'true',}} to {{$prefs['from_addr']}}).

<code type="php">
if (!function_exists('_prefs_hook_from_addr')) {
    function _prefs_hook_from_addr($user = null)
    {
        $domain_name = 'azapple.com';
        $ldapServer = 'localhost';
        $ldapPort = '389';
        $searchBase = 'ou=People,dc=azapple,dc=com';
        $ds = @ldap_connect($ldapServer, $ldapPort);

        if (is_null($user)) {
            $user = Auth::getAuth();
        }

        $uid = Auth::getBareAuth();
        $binddn = 'uid=' . $uid . ',' . $searchBase;
        $bindpw = Auth::getCredential('password');

        if (@ldap_bind($ds, $binddn, $bindpw)) {
            $searchResult = @ldap_search($ds, $searchBase, 'uid=' . $uid);
        }

        $information = @ldap_get_entries($ds, $searchResult);

        // derive the email address if possible
        if ($information['count'] > 0) {
            if ($information[0]['mail'][0] != '') {
                $emailname = $information[0]['mail'][0];
            } else {
                $emailname = $information[0]['uid'][0] . '@' . $domain_name;
            }
        }

        ldap_close($ds);

        return $emailname;
    }
}
</code>

+++++ Fullname #1
The second modification I did to hooks.php was to add the following (don't forget to add the {{'hook' => 'true',}} to {{$prefs['fullname']}}).

<code type="php">
if (!function_exists('_prefs_hook_fullname')) {
    function _prefs_hook_fullname($user = null)
    {
        $ldapServer = 'localhost';
        $ldapPort = '389';
        $searchBase = 'ou=People,dc=azapple,dc=com';
        $ds = @ldap_connect($ldapServer, $ldapPort);

        if (is_null($user)) {
            $user = Auth::getAuth();
        }

        $uid = Auth::getBareAuth();
        $binddn = 'uid=' . $uid . ',' . $searchBase;
        $bindpw = Auth::getCredential('password');

        if (@ldap_bind($ds, $binddn, $bindpw)) {
            $searchResult = @ldap_search($ds, $searchBase, 'uid=' . $uid);
        }

        $information = @ldap_get_entries($ds, $searchResult);

        // derive the email address if possible
        if ($information['count'] > 0) {
            if ($information[0]['cn'][0] != '') {
                $name = $information[0]['cn'][0];
            } else {
                $name = $information[0]['gecos'][0];
            }
        }

        ldap_close($ds);

        return $name;
    }
}
</code>

CW


-----
+++++ Fullname #2

Another way to construct full name from givenName and sn
<code type="php">
if (!function_exists('_prefs_hook_fullname')) {
    function _prefs_hook_fullname($user = null)
    {   
        $ldapServer = '127.0.0.1';
        $ldapPort = '389';
        $searchBase = 'ou=OU_Extern,O=ARNHEM';

        $ds = @ldap_connect($ldapServer, $ldapPort);

        if (is_null($user)) {
            $user = Auth::getAuth();
        }
        $searchResult = @ldap_search($ds, $searchBase, 'cn=' . $user);
        $information = @ldap_get_entries($ds, $searchResult);
        if ($information['count'] > 0) {
            $name = '';
            if ($information[0]['givenName'][0] != '') {
                $name = $information[0]['givenName'][0];

            if ($information[0]['sn'][0] !='') {
                $name = $name . $information[0]['sn'][0];

            if ($name == '') {
                $name = $information[0]['cn'][0];
            }

        ldap_close($ds);

        return (empty($name) ? $user : $name);
    }
}

</code>


</code>
---------
+++++ Fullname #3

This function uses horde's LDAP config to pull the fullname from the LDAP directory.

<code type="php">
if ($GLOBALS['conf']['auth']['driver'] == 'ldap' && !function_exists('_prefs_hook_fullname')) {
    function _prefs_hook_fullname($uid = null)
    {
        global $conf;

        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        $ds = @ldap_connect($conf['auth']['params']['hostspec']);
        @ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $conf['auth']['params']['version']);
        @ldap_bind($ds, $conf['auth']['params']['binddn'], $conf['auth']['params']['password']);
        $searchResult = @ldap_search($ds, $conf['auth']['params']['basedn'], $conf['auth']['params']['uid'] . '=' . $uid);
        $information = @ldap_get_entries($ds, $searchResult);
        ldap_close($ds);

        return $information[0]['displayname'][0];
    }
}
</code>

I have an "events calendar" that all of my users have read-only access to.  This hook makes sure they see that calendar by default.   I had previously just put the pref value in prefs.php, but then a new user's default calendar would not be created and they would not have a "New Event" link in their menu.  (don't forget to add the {{'hook' => 'true'}} to {{$prefs['display_cals']}}).

<code type="php">
if (!function_exists('_prefs_hook_display_cals')) {
    function _prefs_hook_display_cals($uid = null)
    {
        require_once 'Horde/Share.php';

        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        $kronolith_shares = &Horde_Share::singleton('kronolith');
        if (!$kronolith_shares->exists($uid)) {
            require_once 'Horde/Identity.php';
            $identity = &Identity::singleton();
            $name = $identity->getValue('fullname');
            if (trim($name) == '') {
                $name = Auth::removeHook($uid);
            }
            $share = $kronolith_shares->newShare($uid);
            $share->set('name', sprintf(_("%s's Calendar"), $name));
            $kronolith_shares->addShare($share);
        }

        return 'a:2:{i:0;s:' . strlen($uid) . ':"' . $uid . '";i:1;s:32:"ac2bc478568fa773d9a7530b1a71398b";}';
    }
}
</code>

The following compliments the previous function by providing a default {{fb_cals}} pref.

<code type="php">
if (!function_exists('_prefs_hook_fb_cals')) {
    function _prefs_hook_fb_cals($uid = null)
    {
        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        $kronolith_shares = &Horde_Share::singleton('kronolith');
        if (!$kronolith_shares->exists($uid)) {
            require_once 'Horde/Identity.php';
            $identity = &Identity::singleton();
            $name = $identity->getValue('fullname');
            if (trim($name) == '') {
                $name = Auth::removeHook($uid);
            }
            $share = $kronolith_shares->newShare($uid);
            $share->set('name', sprintf(_("%s's Calendar"), $name));
            $kronolith_shares->addShare($share);
        }

        return 'a:1:{i:0;s:' . strlen($uid) . ':"' . $uid . '";}';
    }
}
</code>

This function makes sure that the default "Special" folders exist when a user logs in.
<code type="php">
if (!function_exists('_imp_hook_postlogin')) {
    function _imp_hook_postlogin($actionID, $isLogin)
    {
        $folderlist = $GLOBALS['registry']->callByPackage('imp', 'folderlist', array());

        $folder = $GLOBALS['prefs']->getValue('drafts_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

        $folder = $GLOBALS['prefs']->getValue('sent_mail_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

        $folder = $GLOBALS['prefs']->getValue('spam_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

        $folder = $GLOBALS['prefs']->getValue('trash_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

    }
}
</code>

--Ben Chavet

----

Here
-----
+++++ Fullname #4
Here are some cleaned up hook functions, for populating from_addr and fullname:

<code type="php">
if (!function_exists('_prefs_hook_from_addr')) {
    function _prefs_hook_from_addr($uid = null)
    {
        global $conf;
        $domain_name = 'yourdomain'; // could also use $conf['mailer']['params']['localhost']

        $ldapPort = '389';
        $searchBase = 'yoursearchbase';
        $ds = @ldap_connect($ldapServer, $ldapPort);
       
        if (is_null($uid) {
            $uid = Auth:getAuth();

        // If your search scope is more than one, substitute ldap_search for ldap_list
        if (@ldap_bind($ds)) {
            $searchResult = @ldap_list($ds, $searchBase, $conf['auth']['params']['uid'] . '=' . $uid);

        // derive the email address if possible
        if ($information[0]['mail'][0] != '') {
            $emailname = $information[0]['mail'][0];
        } else {
            $emailname = $information[0]['uid'][0] . '@' . $domain_name;

        ldap_close($ds);

        return $emailname;
    }
}
</code>

<code type="php">
if (!function_exists('_prefs_hook_fullname')) {
   function _prefs_hook_fullname($uid = null)
   {
        global $conf;
        $ldapServer = 'yourdirectoryserver';
        $ldapPort = '389';
        $searchBase = 'yoursearchbase';
        $ds = @ldap_connect($ldapServer, $ldapPort);

        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        if (@ldap_bind($ds)) {


        ldap_close($ds);

        return $name;

KMM


-----

+++++ modifications to connect to the "Active Directory" in the Windows++++ Active Directory 2003 domain

I've made some modifications of KMM's hooks, and inserted new one for the identity's name - ID.
	To work, you have to add the 'hook' => 'true', to $prefs['id'] , to $prefs['fullname'] , and to $prefs['from_addr'] in the prefs.php file.
More info:
- Theese hooks were modified and tested for the "Active Directory" enviroment on the Windows 2003 (+SP2) server/domain.
- Horde was set to authenticate against the same "Active Directory", so conf.php does have all necessary information that may be used later in the hooks.
- Hooks variables containing ldap connection information can be directed to mentioned conf.php .

<code type="php">
if (!function_exists('_prefs_hook_id')) {
   function _prefs_hook_id($uid = null)

        $ldapPort = '3268';
        $binddn = $conf['auth']['params']['binddn'];		// will read the binddn user from the conf.php required to authenticate against ldap. can be changed to 'user@domain.com' .
        $bindpw = $conf['auth']['params']['password'];		// will read the $binddn user's password from the conf.php required to authenticate against ldap. can be changed to simple text = 'PASSWORD' .
        $searchBase = $conf['auth']['params']['basedn'];	// will read the $basedn from the conf.php, but can be changed to = 'ou=SomeOrgUnit,dc=domain,dc=com' .
        $ds = ldap_connect($ldapServer, $ldapPort);
        ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);	// specify the LDAP protocol to use the version 3 .
        ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);		// to be able to perform the searches on Windows 2003 Server Active Directory, this option must be set.

        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        if (ldap_bind($ds, $binddn, $bindpw)) {
            $searchResult = ldap_search($ds, $searchBase, $conf['auth']['params']['uid'] . '=' . $uid);

        // Get the cn or GECOS value; could also pull givenName + sn but that usually == cn
        if ($information[0]['cn'][0] != '') {
            $id = $information[0]['cn'][0];
        } else {
            $id = $information[0]['gecos'][0];
        }

        ldap_close($ds);

        return $id;
    }
}
</code>

<code type="php">
if (!function_exists('_prefs_hook_fullname')) {
   function _prefs_hook_fullname($uid = null)
   {
        global $conf;
        $ldapServer = $conf['auth']['params']['hostspec'];	// will read server info from the conf.php, but can be changed to simple IP address or FQDN if necessary = server.domain.com .
        $ldapPort = '3268';

        $information = ldap_get_entries($ds, $searchResult);

        // Get the cn or GECOS value; could also pull givenName + sn but that usually == cn
        if ($information[0]['cn'][0] != '') {
            $name = $information[0]['cn'][0];
        } else {
            $name = $information[0]['gecos'][0];

        ldap_close($ds);

        return $name;
    }
}
</code>

<code type="php">
if (!function_exists('_prefs_hook_from_addr')) {
    function _prefs_hook_from_addr($uid = null)
    {
        global $conf;
        $domain_name = 'domain.com';
        $ldapServer = $conf['auth']['params']['hostspec'];	// will read server info from the conf.php, but can be changed to simple IP address or FQDN if necessary = server.domain.com .
//        $ldapPort = '3268';
        $binddn = $conf['auth']['params']['binddn'];		// will read the binddn user from the conf.php required to authenticate against ldap. can be changed to 'user@domain.com' .
        $bindpw = $conf['auth']['params']['password'];		// will read the $binddn user's password from the conf.php required to authenticate against ldap. can be changed to simple text = 'PASSWORD' .
        $searchBase = $conf['auth']['params']['basedn'];	// will read the $basedn from the conf.php, but can be changed to = 'ou=SomeOrgUnit,dc=domain,dc=com' .
        $ds = ldap_connect($ldapServer, $ldapPort);
        ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);	// specify the LDAP protocol to use the version 3 .
        ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);		// to be able to perform the searches on Windows 2003 Server Active Directory, this option must be set.

        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        // If your search scope is more than one, substitute ldap_search for ldap_list
        if (ldap_bind($ds, $binddn, $bindpw)) {
            $searchResult = ldap_search($ds, $searchBase, $conf['auth']['params']['uid'] . '=' . $uid);
        }

        $information = ldap_get_entries($ds, $searchResult);

        // derive the email address if possible
        if ($information[0]['mail'][0] != '') {
            $emailname = $information[0]['mail'][0];
        } else {
            $emailname = $information[0]['uid'][0] . '@' . $domain_name;
        }

        ldap_close($ds);

        return $emailname;
    }
}
</code>

Daniel


-----
++++ IMAP #1

For the environments where users are authenticated against IMAP server and all users have at least one email address  with the same domain name like others in the form username@domain.name, you can create a hook which adds this implicit address to the default identity. This can be usefull for Horde modules like WHUPS operate with default e-mail addresses of users. I didn't use preference hook for "from_addr" because what I really needed is not the default address for new identities, but the value for the default identity, even when the identity already exists. From prefs hook I was unable to write to other preferences (do not know why), so I created a postauthentication hook which does everything needed. The only thing I have not resolved is how to tell the preferences cache to update the data immediatelly. But in the database everything is stored so this resolves at the next login automatically.


<code type="php">
require_once('Horde/Identity.php');
if (!function_exists('_horde_hook_postauthenticate')) {
     function _horde_hook_postauthenticate($userID, $credential, $realm)
     {
         $name = "$userID";
         if (is_null($name)) {
             $name = Auth::getAuth();

         if (!empty($name)) {
             $users_identities = &Identity::singleton('none',"$name");
             $users_identities->init();
             $users_identity_default_from_addr = $users_identities->getValue('from_addr');
             if (empty($users_identity_default_from_addr)) {
                 // use your own algorithm here or at least cahnge te domain name to the real value
                 $mail = "$name" . "@example.domain.com"; 
                 // store default identity changes
                 $users_identities->setValue('from_addr',"$mail");
                 $users_identities->save();
             } else {
                 $mail = "$users_identity_default_from_addr";
             }
             // If no email address is found, then the login name will
             // be used.
             return (empty($mail) ? '' : $mail);
         }
         return '';
     }
}
</code>

David Komanek
-----

To make sure only

-----
++++ IMAP #2

Here is a preference hook using "from_addr" you can use to construct the first name listed in LDAP shows up for people with multiple names (the usermail address by using the login.
This tip is from user "TKRIN" and has more than one CN):

<codebeen found on TKRIN website: http://www.tkrin.net/96/trackback/

These changes will automatically fill in the domain portion of the e-mail address in the Default Identity and lock it down so users can not change their e-mail address on the server.

1 ? Edit config/hooks.php and add the following hook:
<code type="php">
if (!function_exists('_turba_hook_decode_name')) {
    function _turba_hook_decode_name($attribute, $turbaObject)
    {
        if (!is_a($turbaObject->driver, 'Turba_Driver_ldap'))(!function_exists('_prefs_hook_from_addr')) {
            return $attribute;
        }

        // Return
  function _prefs_hook_from_addr($user = null)
  {
    if (is_null($user)) {
      $user = Auth::getAuth();
    }
    if (!empty($user)) {
      $user = Auth::getAuth();
      // Here you can add your own code to rework $user and create the mail address from the first name in LDAP
        $namesuser login
      $mail = explode(', ', $attribute);
        return $names[0];"$user" . "@example.com";
      return (empty($mail) ? '' : $mail);
    }
    return '';
  }
}
</code>
2 ? Edit config/prefs.php and change
<code type="php">
$_prefs['from_addr'] = array(
  'value' => '',
  'locked' => true,
  'shared' => true,
  'type' => 'text',
  'desc' => _("Your From: address:")
);
</code>
to
<code type="php">
$_prefs['from_addr'] = array(
  'value' => '',
  'locked' => true,
  'hook' => true,
  'shared' => true,
  'type' => 'text',
  'desc' => _("Your From: address:")
);
</code>

Mathieu RV


-----

add your customizations here...

-----

+++ Horde

++++ Labels / Colors
I have created entries for common categories and common colors for the categories and labels. I am figuring that the entire yellow->orange range is available for people to use for their own purposes and making appointment types in the blue range, personal items in the green spectrum and finally the group categories in red.

<code type="php">
// categories
$_prefs['categories'] = array(
    'value' => 'Appointment - In Office|Appointment - Out of Office|Company Event|Personal Event|Personal Task|Task - Administrative Group|Task - IT Group|Task - Sales Group|Training|Vacation Schedule|Vendor meeting|Holiday',
    'locked' => false,
    'shared' => true,
    'type' => 'implicit'
);
</code>

<code type="php">
// category colors
$_prefs['category_colors'] = array(
    'value' => '1:Appointment - Out of Office|2:Company Event|3:Holiday|4:Personal Event|5:Personal Task|6:Task - Administrative Group|7:Task - IT Group|8:Task - Sales Group|9:Training|10:Vacation Schedule|11:Vendor meeting|12:_default_|13:_unfiled_|14:1|15:2|16:3|17:4|18:5|19:6|20:7|21:8|22:9|23:10|24:11|25:12|26:13|27:14|28:15|29:16|30:17|31:18|32:19|33:20|34:21|35:22|36:23|37:24|38:25|39:26|40:27|41:28|42:29|43:30|44:31|45:32|46:33|47:34|48:35|49:36|50:37|51:38|52:39|53:40|54:41|55:42|56:43|57:44|58:45|59:46|60:47|61:48|62:49|63:50|64:51|65:52|66:53|67:54|68:55|69:56|70:57|71:58|72:59|73:60|74:61|75:62|76:63|77:64|78:65|79:66|80:67|81:68|82:69|83:70|84:71|85:72|86:73|87:74|88:75|89:76|90:77|91:78|92:79|93:80|94:81|95:82|96:83|97:84|98:85|99:86|100:87|101:88|102:89|103:90|104:91|105:92|106:93|107:94|108:95|109:96|110:97|111:98|112:99|113:100|114:101|115:102|116:103|117:104|118:105|119:106|120:107|121:108|122:109|123:110|124:111|125:112|126:113|127:114|128:115|129:116|130:117|131:118|132:119|133:120|134:121|135:122|136:123|137:124|138:125|139:126|140:127|141:128|142:129|143:130|144:131|145:132|146:133|147:134|148:135|149:136|150:137|151:138|152:139|153:140|154:141|155:142|156:143|157:144|158:145|159:146|160:147|161:148|162:149|163:150|164:151|165:152|166:153|167:154|168:155|169:156|170:157|171:158|172:159|173:160|174:161|175:162|176:163|177:164|178:165|179:166|180:167|181:168|182:169|183:170|184:171|185:172|186:173|187:174|188:175|189:176|190:177|191:178|192:179|193:180|194:181|195:194|208:|Appointment - In Office:#0000aa|Appointment - Out of Office:#0000ff|Company Event:#1d1dff|Holiday:#7d7d7d|Personal Event:#7dff7d|Personal Task:#9dff9d|Task - Administrative Group:#ff5f5f|Task - IT Group:#ff7f7f|Task - Sales Group:#ff9f9f|Training:#adadff|Vacation Schedule:#9d9d9d|Vendor meeting:#7d7dff|_default_:#FFFFFF|_unfiled_:#DDDDDD',
    'locked' => false,
    'shared' => true,
    'type' => 'implicit'
);
</code>

Next - and certainly what I think is the most important customization of all possible, is the portal page itself...the main Horde page. This is the sizzle of the steak. This gets people's attention. Of course the weather is for my neck of the woods...

<code type="php">
// the layout of the portal page.
$_prefs['portal_layout'] = array(
    'value' => 'a:4:{i:0;a:2:{i:0;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"fortune";s:6:"params";a:2:{s:6:"offend";s:0:"";s:7:"fortune";a:1:{i:0;s:8:"fortunes";}}}}i:1;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:4:"moon";s:6:"params";a:2:{s:5:"phase";s:7:"current";s:10:"hemisphere";s:8:"northern";}}}}i:1;a:2:{i:0;a:4:{s:3:"app";s:9:"kronolith";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"summary";s:6:"params";a:1:{s:8:"calendar";s:5:"__all";}}}i:1;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:13:"weatherdotcom";s:6:"params";a:3:{s:8:"location";s:22:"Phoenix, AZ (USAZ0166)";s:5:"units";s:8:"standard";s:4:"days";s:1:"3";}}}}i:2;a:2:{i:0;a:4:{s:3:"app";s:3:"nag";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"summary";s:6:"params";a:9:{s:8:"show_pri";s:2:"on";s:12:"show_actions";s:2:"on";s:8:"show_due";s:2:"on";s:13:"show_tasklist";s:2:"on";s:11:"show_alarms";s:2:"on";s:13:"show_category";s:2:"on";s:12:"show_overdue";s:2:"on";s:14:"show_completed";s:2:"on";s:15:"show_categories";a:1:{i:0;s:7:"unfiled";}}}}i:1;a:4:{s:3:"app";s:3:"imp";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"summary";s:6:"params";a:1:{s:11:"show_unread";s:2:"on";}}}}i:3;a:2:{i:0;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"sunrise";s:6:"params";a:2:{s:10:"__location";s:13:"United States";s:8:"location";s:15:"33.434:-112.051";}}}i:1;s:5:"empty";}} }',
    'locked' => false,
    'shared' => false,
    'type' => 'implicit'
);
</code>

CW

-----
++++ Single Sign On
Here is an example of the use of _prefs_change_hook_

We are using a CAS SSO as an Auth Method. So we don't have any horde login page. So what?. Remember that in the login page, you can select which mail frontend you want to use and also get rid of sidebar if dimp is selected. It tooks time to understand how to do that. post_authenticate can't do the job as user prefs are not loaded.

So:
We have to  leave show_sidebar unlock, but people can't modify. To do that, we don't display the value in prefs.php
<code type="php">
$prefGroups['display'] = array(
    'column' => _("Other Information"),
    'label' => _("Display Options"),
    'desc' => _("Set your startup application, color scheme, page refreshing, and other display options."),
    'members' => array('initial_application', 'show_last_login', 'theme',
                     #  'summary_refresh_time', 'show_sidebar', 'sidebar_width', # DOM
                       'summary_refresh_time',  'sidebar_width',
                       'moz_sidebar', 'menu_view', 'menu_refresh_time',
                       'widget_accesskey')


<code type="php">
$this->applications['dimp'] = array(
    'fileroot' => dirname(__FILE__) . '/../dimp',
    'webroot' => $this->applications['horde']['webroot'] . '/dimp',
    'name' => _("Dynamic Mail"),
    'status' => 'active',
    'target' => '_parent',

And then, the change hook:

<code type="php">
if (!function_exists('_prefs_change_hook_initial_application')) {
     function _prefs_change_hook_initial_application()
     {
         $initapp=$GLOBALS['prefs']->getValue('initial_application');
         if (strcmp($initapp,'dimp')==0){
            $GLOBALS['prefs']->setValue('show_sidebar',false);
         }
         else {
            $GLOBALS['prefs']->setValue('show_sidebar',true);
         }
     }
}
</code>

Dominique LALOT

-----

add your customizations here...

-----

+++ Horde

I have created entries for common categories and common colors for the categories and labels. I am figuring that the entire yellow->orange range is available for people to use for their own purposes and making appointment types in the blue range, personal items in the green spectrum and finally the group categories in red.

<code type="php">
// categories
$_prefs['categories'] = array(
    'value' => 'Appointment - In Office|Appointment - Out of Office|Company Event|Personal Event|Personal Task|Task - Administrative Group|Task - IT Group|Task - Sales Group|Training|Vacation Schedule|Vendor meeting|Holiday',
    'locked' => false,
    'shared' => true,
    'type' => 'implicit'
);
</code>

<code type="php">
// category colors
$_prefs['category_colors'] = array(
    'value' => '1:Appointment - Out of Office|2:Company Event|3:Holiday|4:Personal Event|5:Personal Task|6:Task - Administrative Group|7:Task - IT Group|8:Task - Sales Group|9:Training|10:Vacation Schedule|11:Vendor meeting|12:_default_|13:_unfiled_|14:1|15:2|16:3|17:4|18:5|19:6|20:7|21:8|22:9|23:10|24:11|25:12|26:13|27:14|28:15|29:16|30:17|31:18|32:19|33:20|34:21|35:22|36:23|37:24|38:25|39:26|40:27|41:28|42:29|43:30|44:31|45:32|46:33|47:34|48:35|49:36|50:37|51:38|52:39|53:40|54:41|55:42|56:43|57:44|58:45|59:46|60:47|61:48|62:49|63:50|64:51|65:52|66:53|67:54|68:55|69:56|70:57|71:58|72:59|73:60|74:61|75:62|76:63|77:64|78:65|79:66|80:67|81:68|82:69|83:70|84:71|85:72|86:73|87:74|88:75|89:76|90:77|91:78|92:79|93:80|94:81|95:82|96:83|97:84|98:85|99:86|100:87|101:88|102:89|103:90|104:91|105:92|106:93|107:94|108:95|109:96|110:97|111:98|112:99|113:100|114:101|115:102|116:103|117:104|118:105|119:106|120:107|121:108|122:109|123:110|124:111|125:112|126:113|127:114|128:115|129:116|130:117|131:118|132:119|133:120|134:121|135:122|136:123|137:124|138:125|139:126|140:127|141:128|142:129|143:130|144:131|145:132|146:133|147:134|148:135|149:136|150:137|151:138|152:139|153:140|154:141|155:142|156:143|157:144|158:145|159:146|160:147|161:148|162:149|163:150|164:151|165:152|166:153|167:154|168:155|169:156|170:157|171:158|172:159|173:160|174:161|175:162|176:163|177:164|178:165|179:166|180:167|181:168|182:169|183:170|184:171|185:172|186:173|187:174|188:175|189:176|190:177|191:178|192:179|193:180|194:181|195:194|208:|Appointment - In Office:#0000aa|Appointment - Out of Office:#0000ff|Company Event:#1d1dff|Holiday:#7d7d7d|Personal Event:#7dff7d|Personal Task:#9dff9d|Task - Administrative Group:#ff5f5f|Task - IT Group:#ff7f7f|Task - Sales Group:#ff9f9f|Training:#adadff|Vacation Schedule:#9d9d9d|Vendor meeting:#7d7dff|_default_:#FFFFFF|_unfiled_:#DDDDDD',
    'locked' => false,
    'shared' => true,
    'type' => 'implicit'
);
</code>

Next - and certainly what I think is the most important customization of all possible, is the portal page itself...the main Horde page. This is the sizzle of the steak. This gets people's attention. Of course the weather is for my neck of the woods...

<code type="php">
// the layout of the portal page.
$_prefs['portal_layout'] = array(
    'value' => 'a:4:{i:0;a:2:{i:0;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"fortune";s:6:"params";a:2:{s:6:"offend";s:0:"";s:7:"fortune";a:1:{i:0;s:8:"fortunes";}}}}i:1;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:4:"moon";s:6:"params";a:2:{s:5:"phase";s:7:"current";s:10:"hemisphere";s:8:"northern";}}}}i:1;a:2:{i:0;a:4:{s:3:"app";s:9:"kronolith";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"summary";s:6:"params";a:1:{s:8:"calendar";s:5:"__all";}}}i:1;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:13:"weatherdotcom";s:6:"params";a:3:{s:8:"location";s:22:"Phoenix, AZ (USAZ0166)";s:5:"units";s:8:"standard";s:4:"days";s:1:"3";}}}}i:2;a:2:{i:0;a:4:{s:3:"app";s:3:"nag";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"summary";s:6:"params";a:9:{s:8:"show_pri";s:2:"on";s:12:"show_actions";s:2:"on";s:8:"show_due";s:2:"on";s:13:"show_tasklist";s:2:"on";s:11:"show_alarms";s:2:"on";s:13:"show_category";s:2:"on";s:12:"show_overdue";s:2:"on";s:14:"show_completed";s:2:"on";s:15:"show_categories";a:1:{i:0;s:7:"unfiled";}}}}i:1;a:4:{s:3:"app";s:3:"imp";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"summary";s:6:"params";a:1:{s:11:"show_unread";s:2:"on";}}}}i:3;a:2:{i:0;a:4:{s:3:"app";s:5:"horde";s:6:"height";i:1;s:5:"width";i:1;s:6:"params";a:2:{s:4:"type";s:7:"sunrise";s:6:"params";a:2:{s:10:"__location";s:13:"United States";s:8:"location";s:15:"33.434:-112.051";}}}i:1;s:5:"empty";}} }',
    'locked' => false,
    'shared' => false,
    'type' => 'implicit'
);
</code>

CW

-----


-----

add your customizations here...

-----

+++ IMP

++++ Mailboxes polling
I haven't done much with IMP but all my users have these mailboxes and I want them to be 'polled' for new mail when they log on to system (especially the public mail - if there is any 'unseen' mail).

<code type="php">
// list of folders to poll for new mail
$_prefs['nav_poll'] = array(
    'value' => 'a:7:{s:5:"INBOX";b:1;s:19:"INBOX.Deleted Items";b:1;s:12:"INBOX.Drafts";b:1;s:16:"INBOX.Sent Items";b:1;s:13:"INBOX.SPAMBOX";b:1;s:14:"INBOX.VIRUSBOX";b:1;s:6:"public";b:1;}',
    'locked' => false,
    'shared' => false,
    'type' => 'implicit');
</code>

CW

----

-----
++++ Default folders

This function makes sure that the default "Special" folders exist when a user logs in.
<code type="php">
if (!function_exists('_imp_hook_postlogin')) {
    function _imp_hook_postlogin($actionID, $isLogin)
    {
        $folderlist = $GLOBALS['registry']->callByPackage('imp', 'folderlist', array());

        $folder = $GLOBALS['prefs']->getValue('drafts_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

        $folder = $GLOBALS['prefs']->getValue('sent_mail_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

        $folder = $GLOBALS['prefs']->getValue('spam_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

        $folder = $GLOBALS['prefs']->getValue('trash_folder');
        if (!in_array($folder, array_keys($folderlist))) {
            $result = $GLOBALS['registry']->callByPackage('imp', 'createFolder', array('folder' => $folder));
        }

    }
}
</code>

Ben Chavet


-----

add your customizations here...

-----

+++ Ingo

++++ Default filters
Ingo is very clever and it gives you some defaults automatically, but I want to redirect mail already tagged as spam or virus (virus removed naturally) into their respective folders which I have already created for them in my imap configuration. Thus, the default rules additions.

<code type="php">
// filter rules
$_prefs['rules'] = array(
    'value' => 'a:6:{i:0;a:2:{s:4:"name";s:9:"Whitelist";s:6:"action";i:9;}i:1;a:3:{s:4:"name";s:8:"Vacation";s:6:"action";i:8;s:7:"disable";b:1;}i:2;a:2:{s:4:"name";s:9:"Blacklist";s:6:"action";i:7;}i:3;a:2:{s:4:"name";s:7:"Forward";s:6:"action";i:10;}i:4;a:7:{s:4:"name";s:9:"SPAM Flag";s:7:"combine";s:1:"1";s:10:"conditions";a:1:{i:0;a:4:{s:5:"field";s:11:"X-Spam-FLAG";s:4:"type";i:1;s:5:"match";s:8:"contains";s:5:"value";s:3:"YES";}}s:12:"action-value";s:13:"INBOX.SPAMBOX";s:6:"action";s:1:"2";s:4:"stop";s:1:"1";s:5:"flags";i:0;}i:5;a:7:{s:4:"name";s:10:"VIRUS Flag";s:7:"combine";s:1:"1";s:10:"conditions";a:1:{i:0;a:4:{s:5:"field";s:12:"X-Virus-FLAG";s:4:"type";i:1;s:5:"match";s:8:"contains";s:5:"value";s:3:"YES";}}s:12:"action-value";s:14:"INBOX.VIRUSBOX";s:6:"action";s:1:"2";s:4:"stop";s:1:"1";s:5:"flags";i:0;}}',
    'locked' => false,
    'shared' => false,
    'type' => 'implicit'
);

CW

----

add your customizations here...

-----

+++ Kronolith

add++++ Default calendar
I have an "events calendar" that all of my users have read-only access to.  This hook makes sure they see that calendar by default.   I had previously just put the pref value in prefs.php, but then a new user's default calendar would not be created and they would not have a "New Event" link in their menu.  (don't forget to add the {{'hook' => 'true'}} to {{$prefs['display_cals']}}).

<code type="php">
if (!function_exists('_prefs_hook_display_cals')) {
    function _prefs_hook_display_cals($uid = null)
    {
        require_once 'Horde/Share.php';

        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        $kronolith_shares = &Horde_Share::singleton('kronolith');
        if (!$kronolith_shares->exists($uid)) {
            require_once 'Horde/Identity.php';
            $identity = &Identity::singleton();
            $name = $identity->getValue('fullname');
            if (trim($name) == '') {
                $name = Auth::removeHook($uid);
            }
            $share = $kronolith_shares->newShare($uid);
            $share->set('name', sprintf(_("%s's Calendar"), $name));
            $kronolith_shares->addShare($share);
        }

        return 'a:2:{i:0;s:' . strlen($uid) . ':"' . $uid . '";i:1;s:32:"ac2bc478568fa773d9a7530b1a71398b";}';
    }
}
</code>

The following compliments the previous function by providing a default {{fb_cals}} pref.

<code type="php">
if (!function_exists('_prefs_hook_fb_cals')) {
    function _prefs_hook_fb_cals($uid = null)
    {
        if (is_null($uid)) {
            $uid = Auth::getAuth();
        }

        $kronolith_shares = &Horde_Share::singleton('kronolith');
        if (!$kronolith_shares->exists($uid)) {
            require_once 'Horde/Identity.php';
            $identity = &Identity::singleton();
            $name = $identity->getValue('fullname');
            if (trim($name) == '') {
                $name = Auth::removeHook($uid);
            }
            $share = $kronolith_shares->newShare($uid);
            $share->set('name', sprintf(_("%s's Calendar"), $name));
            $kronolith_shares->addShare($share);
        }

        return 'a:1:{i:0;s:' . strlen($uid) . ':"' . $uid . '";}';
    }
}
</code>
-----

add your customizations here...

-----

+++ Mnemo

add your customizations here...

-----

+++ MnemoNag

add your customizations here...

-----

+++ Nag

add your customizations here...Turba
++++ LDAP: Multiple names
To make sure only the first name listed in LDAP shows up for people with multiple names (the user has more than one CN):

<code type="php">
if (!function_exists('_turba_hook_decode_name')) {
    function _turba_hook_decode_name($attribute, $turbaObject)
    {
        if (!is_a($turbaObject->driver, 'Turba_Driver_ldap')) {
            return $attribute;
        }

        // Return the first name in LDAP
        $names = explode(', ', $attribute);
        return $names[0];
    }
}
</code>


-----

+++ Turba

add your customizations here...

-----