6.0.0-git
2020-09-19
Last Modified 2005-07-08 by Jan Schneider

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.php

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']).


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[0]['mail'][0] != '') {

           $emailname = $information[0]['mail'][0];

        } else {

           $emailname = $information[0]['uid'][0] . '@' . $domain_name;

        }

         ldap_close($ds);

         return $emailname;

     }

}

The second modification I did to hooks.php was to add the following (don't forget to add the

'hook' => 'true', to $prefs['fullname']).


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[0]['cn'][0] != '') {

           $name = $information[0]['cn'][0];

        } else {

           $name = $information[0]['gecos'][0];

        }

        ldap_close($ds);

        return $name;

   }

}

CW


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


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];

    }

}

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']).


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";}';

    }

}

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


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 . '";}';

    }

}

--Ben Chavet


Here are some cleaned up hook functions, for populating from_addr and fullname:


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']

       $ldapServer = 'yourdirectoryserver';

       $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);

       }

       $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;

     }

}


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)) {

            $searchResult = @ldap_list($ds, $searchBase, 'uid=' . $uid);

        }

        $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;

   }

}

KMM


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 prefes 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.

The code works following way: if you have no default identity yet, it is created for you. If you have no e-mail address

in the default identity, it is stored there as a composition of your username and default domain name (more complicated

algorithms can be used here as well).


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 '';

     }

}

David Komanek


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.


// 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'

);


// 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'

);

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...


// 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'

);

CW


add your customizations here...


IMP

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).


// 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');

CW


add your customizations here...


Ingo

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.


// 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 your customizations here...


Mnemo

add your customizations here...


Nag

add your customizations here...


Turba

add your customizations here...