Overview

Packages

  • Auth
  • Core
  • Horde
    • Imsp
  • None
  • Notification

Classes

  • Horde
  • Horde_Config
  • Horde_Config_Form
  • Horde_Core_ActiveSync_Connector
  • Horde_Core_ActiveSync_Driver
  • Horde_Core_Ajax_Application
  • Horde_Core_Ajax_Imple
  • Horde_Core_Ajax_Imple_AutoCompleter
  • Horde_Core_Ajax_Imple_Geocoder_Geonames
  • Horde_Core_Ajax_Imple_SpellChecker
  • Horde_Core_Alarm_Handler_Notify
  • Horde_Core_Auth_Application
  • Horde_Core_Auth_Composite
  • Horde_Core_Auth_Ldap
  • Horde_Core_Auth_Msad
  • Horde_Core_Auth_Shibboleth
  • Horde_Core_Auth_Signup_Base
  • Horde_Core_Auth_Signup_Form
  • Horde_Core_Auth_Signup_Null
  • Horde_Core_Auth_Signup_Sql
  • Horde_Core_Auth_Signup_SqlObject
  • Horde_Core_Autoloader_Callback_Mime
  • Horde_Core_Autoloader_Callback_Nls
  • Horde_Core_Block
  • Horde_Core_Block_Collection
  • Horde_Core_Block_Layout
  • Horde_Core_Block_Layout_Manager
  • Horde_Core_Block_Layout_View
  • Horde_Core_Block_Upgrade
  • Horde_Core_Browser
  • Horde_Core_Bundle
  • Horde_Core_Cli
  • Horde_Core_Controller_NotFound
  • Horde_Core_Controller_RequestConfiguration
  • Horde_Core_Controller_RequestMapper
  • Horde_Core_Controller_SettingsFinder
  • Horde_Core_Db_Migration
  • Horde_Core_Factory_ActiveSyncBackend
  • Horde_Core_Factory_ActiveSyncServer
  • Horde_Core_Factory_ActiveSyncState
  • Horde_Core_Factory_Ajax
  • Horde_Core_Factory_Alarm
  • Horde_Core_Factory_Auth
  • Horde_Core_Factory_AuthSignup
  • Horde_Core_Factory_Base
  • Horde_Core_Factory_BlockCollection
  • Horde_Core_Factory_Browser
  • Horde_Core_Factory_Cache
  • Horde_Core_Factory_Crypt
  • Horde_Core_Factory_Data
  • Horde_Core_Factory_Db
  • Horde_Core_Factory_DbBase
  • Horde_Core_Factory_DbPear
  • Horde_Core_Factory_Dns
  • Horde_Core_Factory_Editor
  • Horde_Core_Factory_Facebook
  • Horde_Core_Factory_Group
  • Horde_Core_Factory_History
  • Horde_Core_Factory_HttpClient
  • Horde_Core_Factory_Identity
  • Horde_Core_Factory_Image
  • Horde_Core_Factory_Imple
  • Horde_Core_Factory_Imsp
  • Horde_Core_Factory_ImspAuth
  • Horde_Core_Factory_Injector
  • Horde_Core_Factory_KolabServer
  • Horde_Core_Factory_KolabSession
  • Horde_Core_Factory_KolabStorage
  • Horde_Core_Factory_Ldap
  • Horde_Core_Factory_Lock
  • Horde_Core_Factory_Logger
  • Horde_Core_Factory_LoginTasks
  • Horde_Core_Factory_Mail
  • Horde_Core_Factory_Mapper
  • Horde_Core_Factory_Matcher
  • Horde_Core_Factory_Memcache
  • Horde_Core_Factory_MimeViewer
  • Horde_Core_Factory_Notification
  • Horde_Core_Factory_Perms
  • Horde_Core_Factory_PermsCore
  • Horde_Core_Factory_Prefs
  • Horde_Core_Factory_Request
  • Horde_Core_Factory_Secret
  • Horde_Core_Factory_SessionHandler
  • Horde_Core_Factory_Share
  • Horde_Core_Factory_ShareBase
  • Horde_Core_Factory_Template
  • Horde_Core_Factory_TextFilter
  • Horde_Core_Factory_ThemesCache
  • Horde_Core_Factory_Token
  • Horde_Core_Factory_Tree
  • Horde_Core_Factory_Twitter
  • Horde_Core_Factory_UrlShortener
  • Horde_Core_Factory_Vfs
  • Horde_Core_Factory_View
  • Horde_Core_Factory_Weather
  • Horde_Core_Group_Ldap
  • Horde_Core_Log_Logger
  • Horde_Core_LoginTasks
  • Horde_Core_LoginTasks_Backend_Horde
  • Horde_Core_LoginTasks_SystemTask_Upgrade
  • Horde_Core_Mime_Viewer_Syntaxhighlighter
  • Horde_Core_Mime_Viewer_Vcard
  • Horde_Core_Notification_Event_Status
  • Horde_Core_Notification_Handler_Decorator_Hordelog
  • Horde_Core_Notification_Storage_Session
  • Horde_Core_Perms
  • Horde_Core_Perms_Ui
  • Horde_Core_Prefs_Cache_Session
  • Horde_Core_Prefs_Identity
  • Horde_Core_Prefs_Storage_Configuration
  • Horde_Core_Prefs_Storage_Hooks
  • Horde_Core_Prefs_Storage_Upgrade
  • Horde_Core_Prefs_Ui
  • Horde_Core_Prefs_Ui_Widgets
  • Horde_Core_Share_Driver
  • Horde_Core_Share_FactoryCallback
  • Horde_Core_Sidebar
  • Horde_Core_Text_Filter_Bbcode
  • Horde_Core_Text_Filter_Emails
  • Horde_Core_Text_Filter_Emoticons
  • Horde_Core_Text_Filter_Highlightquotes
  • Horde_Core_Translation
  • Horde_Core_Tree_Html
  • Horde_Core_Tree_Javascript
  • Horde_Core_Tree_Simplehtml
  • Horde_Core_Ui_FlagImage
  • Horde_Core_Ui_JsCalendar
  • Horde_Core_Ui_Language
  • Horde_Core_Ui_Layout
  • Horde_Core_Ui_ModalFormRenderer
  • Horde_Core_Ui_Pager
  • Horde_Core_Ui_Tabs
  • Horde_Core_Ui_TagCloud
  • Horde_Core_Ui_VarRenderer
  • Horde_Core_Ui_VarRenderer_Html
  • Horde_Core_Ui_VarRenderer_TablesetHtml
  • Horde_Core_Ui_Widget
  • Horde_ErrorHandler
  • Horde_Help
  • Horde_Menu
  • Horde_Registry
  • Horde_Registry_Api
  • Horde_Registry_Application
  • Horde_Registry_Caller
  • Horde_Registry_Nlsconfig
  • Horde_Script_Files
  • Horde_Session
  • Horde_Session_Null
  • Horde_Themes
  • Horde_Themes_Cache
  • Horde_Themes_Css
  • Horde_Themes_Element
  • Horde_Themes_Image
  • Horde_Themes_Sound

Exceptions

  • Horde_Exception_HookNotSet
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Class for generating/processing the preferences UI.
  4:  *
  5:  * See Horde_Registry_Application:: for a summary of the API callbacks that
  6:  * are available.
  7:  *
  8:  * Session variables set (stored in 'horde_prefs'):
  9:  * 'advanced' - (boolean) If true, display advanced prefs.
 10:  *
 11:  * Copyright 2001-2012 Horde LLC (http://www.horde.org/)
 12:  *
 13:  * See the enclosed file COPYING for license information (LGPL). If you
 14:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 15:  *
 16:  * @author   Chuck Hagenbuch <chuck@horde.org>
 17:  * @author   Michael Slusarz <slusarz@horde.org>
 18:  * @category Horde
 19:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 20:  * @package  Core
 21:  */
 22: class Horde_Core_Prefs_Ui
 23: {
 24:     /**
 25:      * Preferences groups.
 26:      *
 27:      * @var array
 28:      */
 29:     public $prefGroups = array();
 30: 
 31:     /**
 32:      * Preferences.
 33:      *
 34:      * @var array
 35:      */
 36:     public $prefs = array();
 37: 
 38:     /**
 39:      * Data overrides (for 'enum' and 'multienum' types).
 40:      *
 41:      * @var array
 42:      */
 43:     public $override = array();
 44: 
 45:     /**
 46:      * Suppressed preference entries.
 47:      *
 48:      * @var array
 49:      */
 50:     public $suppress = array();
 51: 
 52:     /**
 53:      * Suppressed prefGroup entries.
 54:      *
 55:      * @var array
 56:      */
 57:     public $suppressGroups = array();
 58: 
 59:     /**
 60:      * Current application.
 61:      *
 62:      * @var string
 63:      */
 64:     public $app;
 65: 
 66:     /**
 67:      * Current preferences group.
 68:      *
 69:      * @var string
 70:      */
 71:     public $group;
 72: 
 73:     /**
 74:      * Form variables for this page load.
 75:      *
 76:      * @var Horde_Variables
 77:      */
 78:     public $vars;
 79: 
 80:     /**
 81:      * If set, suppresses display of the buttons.
 82:      *
 83:      * @var boolean
 84:      */
 85:     public $nobuttons = false;
 86: 
 87:     /**
 88:      * List of update errors.
 89:      *
 90:      * @var array
 91:      */
 92:     protected $_errors = array();
 93: 
 94:     /**
 95:      * Constructor.
 96:      *
 97:      * @param Horde_Variables $vars  Form variables.
 98:      */
 99:     public function __construct($vars)
100:     {
101:         global $registry;
102: 
103:         $this->app = isset($vars->app)
104:             ? $vars->app
105:             : $this->getDefaultApp();
106:         $this->group = $vars->group;
107:         $this->vars = $vars;
108: 
109:         /* Load the application's base environment. */
110:         try {
111:             $registry->pushApp($this->app);
112:         } catch (Horde_Exception $e) {
113:             if ($e->getCode() == Horde_Registry::AUTH_FAILURE) {
114:                 $registry->authenticateFailure($this->app, $e);
115:             }
116:             throw $e;
117:         }
118: 
119:         /* Load preferences. */
120:         $this->_loadPrefs($this->app);
121: 
122:         /* Run app-specific init code. */
123:         $registry->callAppMethod($this->app, 'prefsInit', array('args' => array($this)));
124: 
125:         if ($this->group &&
126:             !in_array($this->group, $this->suppressGroups)) {
127:             $registry->callAppMethod($this->app, 'prefsGroup', array('args' => array($this)));
128:         }
129:     }
130: 
131:     /**
132:      * Determine whether or not a preferences group is editable.
133:      *
134:      * @param string $group  The preferences group to check.
135:      *
136:      * @return boolean  Whether or not the group is editable.
137:      */
138:     public function groupIsEditable($group)
139:     {
140:         return (bool)count($this->getChangeablePrefs($group));
141:     }
142: 
143:     /**
144:      * Returns the list of changeable prefs for a group.
145:      *
146:      * @param string $group  The preferences group to check.
147:      *
148:      * @return array  The list of changeable prefs.
149:      */
150:     public function getChangeablePrefs($group = null)
151:     {
152:         if (is_null($group)) {
153:             if (!$this->group) {
154:                 return array();
155:             }
156: 
157:             $group = $this->group;
158:         }
159: 
160:         return (empty($this->prefGroups[$group]['members']) ||
161:                 in_array($group, $this->suppressGroups))
162:             ? array()
163:             : $this->_getChangeablePrefs($this->prefGroups[$group]['members']);
164:     }
165: 
166:     /**
167:      * Returns the list of changeable prefs.
168:      *
169:      * @param array $preflist  The list of preferences to check.
170:      *
171:      * @return array  The list of changeable prefs.
172:      */
173:     protected function _getChangeablePrefs($preflist)
174:     {
175:         $cprefs = array();
176: 
177:         foreach ($preflist as $pref) {
178:             /* Changeable pref if:
179:              *   1. Not locked
180:              *   2. Not in suppressed array ($this->suppress)
181:              *   3. Not an advanced pref -or- in advanced view mode
182:              *   4. Not an implicit pref */
183:             if (!$GLOBALS['prefs']->isLocked($pref) &&
184:                 !in_array($pref, $this->suppress) &&
185:                 (empty($this->prefs[$pref]['advanced']) ||
186:                  $GLOBALS['session']->get('horde', 'prefs_advanced')) &&
187:                 ((!empty($this->prefs[$pref]['type']) &&
188:                  ($this->prefs[$pref]['type'] != 'implicit')))) {
189:                 if ($this->prefs[$pref]['type'] == 'container') {
190:                     if (isset($this->prefs[$pref]['value']) &&
191:                         is_array($this->prefs[$pref]['value'])) {
192:                         $cprefs = array_merge($cprefs, $this->prefs[$pref]['value']);
193:                     }
194:                 } else {
195:                     $cprefs[] = $pref;
196:                 }
197:             }
198:         }
199: 
200:         return $cprefs;
201:     }
202: 
203:     /**
204:      * Returns whether advanced preferences exist in the current application.
205:      *
206:      * @return boolean  True if at least one of the preferences is an advanced
207:      *                  preference.
208:      */
209:     public function hasAdvancedPrefs()
210:     {
211:         foreach ($this->_getPrefGroups() as $group) {
212:             if (empty($group['members'])) {
213:                 continue;
214:             }
215:             foreach ($group['members'] as $pref) {
216:                 if (!empty($this->prefs[$pref]['advanced'])) {
217:                     return true;
218:                 }
219:             }
220:         }
221:         return false;
222:     }
223: 
224:     /**
225:      * Handle a preferences form submission if there is one, updating
226:      * any preferences which have been changed.
227:      */
228:     public function handleForm()
229:     {
230:         /* Toggle Advanced/Basic mode. */
231:         if (!empty($this->vars->show_advanced) ||
232:             !empty($this->vars->show_basic)) {
233:             $GLOBALS['session']->set('horde', 'prefs_advanced', !empty($this->vars->show_advanced));
234:         } elseif (!$this->vars->actionID ||
235:                   !$this->group ||
236:                   !$this->groupIsEditable($this->group)) {
237:             return;
238:         } elseif (isset($this->vars->prefs_return)) {
239:             $this->group = $this->vars->actionID = '';
240:             return;
241:         } else {
242:             try {
243:                 $GLOBALS['injector']->getInstance('Horde_Token')->validate($this->vars->horde_prefs_token, 'horde.prefs');
244:             } catch (Horde_Token_Exception $e) {
245:                 $GLOBALS['notification']->push($e);
246:                 return;
247:             }
248:         }
249: 
250:         switch ($this->vars->actionID) {
251:         case 'update_prefs':
252:             if (isset($this->prefGroups[$this->group]['type']) &&
253:                 ($this->prefGroups[$this->group]['type'] == 'identities')) {
254:                 $this->_identitiesUpdate();
255:             } else {
256:                 $this->_handleForm($this->getChangeablePrefs($this->group), $GLOBALS['prefs']);
257:             }
258:             break;
259: 
260:         case 'update_special':
261:             $special = array();
262:             foreach ($this->getChangeablePrefs($this->group) as $pref) {
263:                 if ($this->prefs[$pref]['type'] == 'special') {
264:                     $special[] = $pref;
265:                 }
266:             }
267:             $this->_handleForm($special, $GLOBALS['prefs']);
268:             break;
269:         }
270: 
271:         $this->nobuttons = false;
272:         $this->suppress = array();
273:         $GLOBALS['registry']->callAppMethod($this->app, 'prefsGroup', array('args' => array($this)));
274:     }
275: 
276:     /*
277:      * Handle a preferences form submission if there is one, updating
278:      * any preferences which have been changed.
279:      *
280:      * @param array $preflist  The list of preferences to process.
281:      * @param mixed $save      The object to save preferences values to.
282:      */
283:     protected function _handleForm($preflist, $save)
284:     {
285:         global $notification, $prefs, $registry;
286: 
287:         $updated = false;
288: 
289:         /* Run through the action handlers */
290:         foreach ($preflist as $pref) {
291:             switch ($this->prefs[$pref]['type']) {
292:             case 'checkbox':
293:                 $updated |= $save->setValue($pref, intval(isset($this->vars->$pref)));
294:                 break;
295: 
296:             case 'enum':
297:                 $enum = isset($this->override[$pref])
298:                     ? $this->override[$pref]
299:                     : $this->prefs[$pref]['enum'];
300:                 if (isset($enum[$this->vars->$pref])) {
301:                     $updated |= $save->setValue($pref, $this->vars->$pref);
302:                 } else {
303:                     $this->_errors[$pref] = Horde_Core_Translation::t("An illegal value was specified.");
304:                 }
305:                 break;
306: 
307:             case 'multienum':
308:                 $set = array();
309: 
310:                 if (is_array($this->vars->$pref)) {
311:                     $enum = isset($this->override[$pref])
312:                         ? $this->override[$pref]
313:                         : $this->prefs[$pref]['enum'];
314: 
315:                     foreach ($this->vars->$pref as $val) {
316:                         if (isset($enum[$val])) {
317:                             $set[] = $val;
318:                         } else {
319:                             $this->_errors[$pref] = Horde_Core_Translation::t("An illegal value was specified.");
320:                             break 2;
321:                         }
322:                     }
323:                 }
324: 
325:                 $updated |= $save->setValue($pref, @serialize($set));
326:                 break;
327: 
328:             case 'number':
329:                 $num = $this->vars->$pref;
330:                 if ((string)(double)$num !== $num) {
331:                     $this->_errors[$pref] = Horde_Core_Translation::t("This value must be a number.");
332:                 } elseif (empty($num) && empty($this->prefs[$pref]['zero'])) {
333:                     $this->_errors[$pref] = Horde_Core_Translation::t("This value must be non-zero.");
334:                 } else {
335:                     $updated |= $save->setValue($pref, $num);
336:                 }
337:                 break;
338: 
339:             case 'password':
340:             case 'text':
341:             case 'textarea':
342:                 $updated |= $save->setValue($pref, $this->vars->$pref);
343:                 break;
344: 
345: 
346:             case 'special':
347:                 /* Code for special elements written specifically for each
348:                  * application. */
349:                 $updated = $updated | (bool)$registry->callAppMethod($this->app, 'prefsSpecialUpdate', array('args' => array($this, $pref)));
350:                 break;
351:             }
352:         }
353: 
354:         if (count($this->_errors)) {
355:             $notification->push(Horde_Core_Translation::t("There were errors encountered while updating your preferences."), 'horde.error');
356:         }
357: 
358:         if ($updated) {
359:             if ($save instanceof Horde_Prefs_Identity) {
360:                 // Throws Exception caught in _identitiesUpdate().
361:                 $save->verify();
362:             }
363: 
364:             $registry->callAppMethod($this->app, 'prefsCallback', array('args' => array($this)));
365: 
366:             if ($prefs instanceof Horde_Prefs_Session) {
367:                 $notification->push(Horde_Core_Translation::t("Your preferences have been updated for the duration of this session."), 'horde.success');
368:             } else {
369:                 $notification->push(Horde_Core_Translation::t("Your preferences have been updated."), 'horde.success');
370:             }
371: 
372:             $this->_loadPrefs($this->app);
373:         }
374:     }
375: 
376:     /**
377:      * Returns a self URL to the current page.
378:      *
379:      * @param array $options  Additional options:
380:      * <pre>
381:      * 'special' - (boolean) If set, will trigger special action update
382:      *             processing when the URL is loaded.
383:      * 'token' - (boolean) If set, includes the form token in the URL.
384:      * </pre>
385:      *
386:      * @return Horde_Url  The URL object.
387:      */
388:     public function selfUrl($options = array())
389:     {
390:         $url = Horde::getServiceLink('prefs', $this->app);
391:         if ($this->group) {
392:             $url->add('group', $this->group);
393:         }
394:         if (!empty($options['special'])) {
395:             $url->add('actionID', 'update_special');
396:         }
397:         if (!empty($options['token'])) {
398:             $url->add('horde_prefs_token', $GLOBALS['injector']->getInstance('Horde_Token')->get('horde.prefs'));
399:         }
400:         return $url;
401:     }
402: 
403:     /**
404:      * Generate the UI for the preferences interface, either for a
405:      * specific group, or the group selection interface.
406:      */
407:     public function generateUI()
408:     {
409:         global $notification, $prefs, $registry;
410: 
411:         $columns = $pref_list = array();
412:         $identities = false;
413: 
414:         $prefgroups = $this->_getPrefGroups();
415: 
416:         if ($this->group) {
417:             $pref_list = $this->getChangeablePrefs($this->group);
418:             if (empty($pref_list)) {
419:                 $this->group = '';
420:                 $this->generateUI();
421:                 return;
422:             }
423: 
424:             /* Add necessary init stuff for identities pages. */
425:             if (isset($prefgroups[$this->group]['type']) &&
426:                 ($prefgroups[$this->group]['type'] == 'identities')) {
427:                 Horde::addScriptFile('identityselect.js', 'horde');
428:                 $identities = true;
429: 
430:                 /* If this is an identities group, need to grab the base
431:                  * identity fields from Horde, if current app is NOT Horde. */
432:                 $pref_list = $this->_addHordeIdentitiesPrefs($pref_list);
433:             }
434:         } else {
435:             foreach ($prefgroups as $key => $val) {
436:                 $columns[$val['column']][$key] = $val;
437:             }
438:         }
439: 
440:         if (empty($columns) && empty($pref_list)) {
441:             $notification->push(Horde_Core_Translation::t("There are no preferences available for this application."), 'horde.message');
442:             $this->nobuttons = true;
443:         }
444: 
445:         $options_link = Horde::getServiceLink('prefs');
446:         $h_templates = $registry->get('templates', 'horde');
447: 
448:         $base = $GLOBALS['injector']->createInstance('Horde_Template');
449:         $base->setOption('gettext', true);
450: 
451:         /* Need to buffer output - it is possible that 'special' types can
452:          * do things like add javascript to the page output. This should all
453:          * be combined and served in the page HEAD. */
454:         Horde::startBuffer();
455:         Horde::addScriptFile('prefs.js', 'horde');
456: 
457:         if ($this->group) {
458:             if ($identities) {
459:                 echo $this->_identityHeader($pref_list);
460:             }
461: 
462:             foreach ($pref_list as $pref) {
463:                 if ($this->prefs[$pref]['type'] == 'special') {
464:                     echo $registry->callAppMethod($this->app, 'prefsSpecial', array('args' => array($this, $pref)));
465:                     continue;
466:                 }
467: 
468:                 $t = clone $base;
469: 
470:                 if (isset($this->_errors[$pref])) {
471:                     echo $t->fetch(HORDE_TEMPLATES . '/prefs/error_start.html');
472:                 }
473: 
474:                 if (isset($this->prefs[$pref]['desc'])) {
475:                     $t->set('desc', Horde::label($pref, $this->prefs[$pref]['desc']));
476:                 }
477:                 $t->set('helplink', empty($this->prefs[$pref]['help']) ? null : Horde_Help::link(empty($this->prefs[$pref]['shared']) ? $this->app : 'horde', $this->prefs[$pref]['help']));
478:                 $t->set('pref', htmlspecialchars($pref));
479: 
480:                 $type = $this->prefs[$pref]['type'];
481:                 switch ($type) {
482:                 case 'checkbox':
483:                     $t->set('checked', $prefs->getValue($pref));
484:                     break;
485: 
486:                 case 'enum':
487:                     $enum = isset($this->override[$pref])
488:                         ? $this->override[$pref]
489:                         : $this->prefs[$pref]['enum'];
490:                     $esc = !empty($this->prefs[$pref]['escaped']);
491:                     $curval = $prefs->getValue($pref);
492: 
493:                     $tmp = array();
494:                     foreach ($enum as $key => $val) {
495:                         $tmp[] = array(
496:                             'l' => $esc ? $val : htmlspecialchars($val),
497:                             's' => ($curval == $key),
498:                             'v' => $esc ? $key : htmlspecialchars($key)
499:                         );
500:                     }
501:                     $t->set('enum', $tmp);
502:                     break;
503: 
504:                 case 'prefslink':
505:                     $url = $this->selfUrl()->add('group', $this->prefs[$pref]['group']);
506:                     if (!empty($this->prefs[$pref]['app'])) {
507:                         $url->add('app', $this->prefs[$pref]['app']);
508:                     }
509:                     $this->prefs[$pref]['url'] = $url;
510:                     $type = 'link';
511:                     // Fall through to 'link'
512: 
513:                 case 'link':
514:                     if (isset($this->prefs[$pref]['img'])) {
515:                         $t->set('img', Horde::img($this->prefs[$pref]['img'], $this->prefs[$pref]['desc'], array('class' => 'prefsLinkImg')));
516:                     }
517:                     $t->set('url', isset($this->prefs[$pref]['url']) ? Horde::url($this->prefs[$pref]['url']) : $this->prefs[$pref]['xurl']);
518:                     if (isset($this->prefs[$pref]['target'])) {
519:                         $t->set('target', htmlspecialchars($this->prefs[$pref]['target']));
520:                     }
521:                     break;
522: 
523:                 case 'multienum':
524:                     $enum = isset($this->override[$pref])
525:                         ? $this->override[$pref]
526:                         : $this->prefs[$pref]['enum'];
527:                     $esc = !empty($this->prefs[$pref]['escaped']);
528:                     if (!$selected = @unserialize($prefs->getValue($pref))) {
529:                         $selected = array();
530:                     }
531: 
532:                     $tmp = array();
533:                     foreach ($enum as $key => $val) {
534:                         $tmp[] = array(
535:                             'l' => $esc ? $val : htmlspecialchars($val),
536:                             's' => in_array($key, $selected),
537:                             'v' => $esc ? $key : htmlspecialchars($key)
538:                         );
539:                     }
540:                     $t->set('enum', $tmp);
541: 
542:                     $t->set('size', min(4, count($enum)));
543:                     break;
544: 
545:                 case 'number':
546:                     $t->set('val', htmlspecialchars(intval($prefs->getValue($pref))));
547:                     break;
548: 
549:                 case 'password':
550:                 case 'text':
551:                 case 'textarea':
552:                     $t->set('val', htmlspecialchars($prefs->getValue($pref)));
553:                     break;
554: 
555:                 case 'rawhtml':
556:                     $t->set('html', $prefs->getValue($pref));
557:                     break;
558:                 }
559: 
560:                 echo $t->fetch(HORDE_TEMPLATES . '/prefs/' . $type . '.html');
561: 
562:                 if (isset($this->_errors[$pref])) {
563:                     $t->set('error', htmlspecialchars($this->_errors[$pref]));
564:                     echo $t->fetch(HORDE_TEMPLATES . '/prefs/error_end.html');
565:                 }
566:             }
567: 
568:             $t = clone $base;
569:             $t->set('buttons', !$this->nobuttons);
570:             $t->set('prefgroups', count($prefgroups) > 1);
571:             echo $t->fetch($h_templates . '/prefs/end.html');
572:         } elseif (!empty($columns)) {
573:             $t = clone $base;
574:             $span = round(100 / count($columns));
575: 
576:             $cols = array();
577:             foreach ($columns as $key => $column) {
578:                 $tmp = array(
579:                     'groups' => array(),
580:                     'hdr' => htmlspecialchars($key),
581:                     'width' => $span - 1
582:                 );
583: 
584:                 foreach ($column as $group => $gvals) {
585:                     if ($this->groupIsEditable($group)) {
586:                         $tmp['groups'][] = array(
587:                             'desc' => htmlspecialchars($gvals['desc']),
588:                             'link' => Horde::widget($options_link->copy()->add(array('app' => $this->app, 'group' => $group)), $gvals['label'], '', '', '', $gvals['label'])
589:                         );
590:                     }
591:                 }
592:                 $cols[] = $tmp;
593:             }
594:             $t->set('columns', $cols);
595: 
596:             echo $t->fetch($h_templates . '/prefs/overview.html');
597:         }
598: 
599:         $content = Horde::endBuffer();
600: 
601:         $title = Horde_Core_Translation::t("User Preferences");
602: 
603:         /* Get the menu output before we start to output the page.
604:          * Again, this will catch any javascript inserted into the page. */
605:         $menu_out = $this->vars->ajaxui
606:             ? ''
607:             : Horde::menu(array(
608:                   'app' => $this->app,
609:               ));
610: 
611:         /* Get list of accessible applications. */
612:         $apps = array();
613:         foreach ($registry->listApps() as $app) {
614:             // Make sure the app is installed and has a prefs file.
615:             if (file_exists($registry->get('fileroot', $app) . '/config/prefs.php')) {
616:                 $apps[$app] = $registry->get('name', $app);
617:             }
618:         }
619:         asort($apps);
620: 
621:         /* Ouptut screen. */
622:         $GLOBALS['bodyId'] = 'services_prefs';
623:         require $h_templates . '/common-header.inc';
624:         echo $menu_out;
625: 
626:         $notification->notify(array('listeners' => 'status'));
627: 
628:         $base_ui = clone $base;
629:         $base_ui->set('action', $options_link);
630:         $base_ui->set('ajaxui', intval($this->vars->ajaxui));
631:         $base_ui->set('forminput', Horde_Util::formInput());
632: 
633:         /* Show the current application and a form for switching
634:          * applications. */
635:         $t = clone $base_ui;
636:         $t->set('horde', !empty($apps['horde']) && ($this->app != 'horde'));
637:         unset($apps['horde'], $apps[$this->app]);
638:         $tmp = array();
639:         foreach ($apps as $key => $val) {
640:             $tmp[] = array(
641:                 'l' => htmlspecialchars($val),
642:                 'v' => htmlspecialchars($key)
643:             );
644:         }
645:         $t->set('apps', $tmp);
646:         $t->set('header', htmlspecialchars(($this->app == 'horde') ? Horde_Core_Translation::t("Global Preferences") : sprintf(Horde_Core_Translation::t("Preferences for %s"), $registry->get('name', $this->app))));
647: 
648:         $t->set('has_advanced', $this->hasAdvancedPrefs());
649:         if ($GLOBALS['session']->get('horde', 'prefs_advanced')) {
650:             $t->set('basic', $this->selfUrl()->add('show_basic', 1));
651:         } else {
652:             $t->set('advanced', $this->selfUrl()->add('show_advanced', 1));
653:         }
654: 
655:         echo $t->fetch($h_templates . '/prefs/app.html');
656: 
657:         /* Generate navigation header. */
658:         if ($this->group) {
659:             $t = clone $base_ui;
660:             $t->set('app', htmlspecialchars($this->app));
661:             $t->set('group', htmlspecialchars($this->group));
662:             $t->set('label', htmlspecialchars($this->prefGroups[$this->group]['label']));
663:             $t->set('token', $GLOBALS['injector']->getInstance('Horde_Token')->get('horde.prefs'));
664: 
665:             // Search for previous and next groups.
666:             if (count($prefgroups) > 1) {
667:                 $prefgroups = array_keys($prefgroups);
668:                 $key = array_search($this->group, $prefgroups);
669:                 $previous = isset($prefgroups[$key - 1])
670:                     ? $prefgroups[$key - 1]
671:                     : end($prefgroups);
672:                 $next = isset($prefgroups[$key + 1])
673:                     ? $prefgroups[$key + 1]
674:                     : reset($prefgroups);
675:                 $prefs_url = $this->selfUrl();
676: 
677:                 $t->set('prev', $prefs_url->copy()->add('group', $previous));
678:                 $t->set('prevlabel', htmlspecialchars($this->prefGroups[$previous]['label']));
679:                 $t->set('previcon', Horde::img('nav/left.png'));
680:                 $t->set('next', $prefs_url->copy()->add('group', $next));
681:                 $t->set('nextlabel', htmlspecialchars($this->prefGroups[$next]['label']));
682:                 $t->set('nexticon', Horde::img('nav/right.png'));
683:             }
684: 
685:             echo $t->fetch($h_templates . '/prefs/begin.html');
686:         }
687: 
688:         echo $content;
689: 
690:         require $h_templates . '/common-footer.inc';
691:     }
692: 
693:     /**
694:      * Get the default application to show preferences for. Defaults
695:      * to 'horde'.
696:      *
697:      * @return string  The default application.
698:      */
699:     public function getDefaultApp()
700:     {
701:         $applications = $GLOBALS['registry']->listApps(null, true, Horde_Perms::READ);
702:         return isset($applications['horde'])
703:             ? 'horde'
704:             : array_shift($applications);
705:     }
706: 
707:     /**
708:      * Parses/loads preferences configuration.
709:      *
710:      * @param string $app    The application.
711:      * @param boolean $data  Return the data instead of loading into the
712:      *                       current object?
713:      */
714:     protected function _loadPrefs($app, $data = false)
715:     {
716:         try {
717:             $res = Horde::loadConfiguration('prefs.php', array('prefGroups', '_prefs'), $app);
718:         } catch (Horde_Exception $e) {
719:             $res = array('prefGroups' => array(), '_prefs' => array());
720:         }
721: 
722:         if ($data) {
723:             return $res;
724:         }
725: 
726:         $this->prefGroups = isset($res['prefGroups'])
727:             ? $res['prefGroups']
728:             : array();
729:         $this->prefs = $res['_prefs'];
730: 
731:         /* If there's only one prefGroup, just show it. */
732:         if (!$this->group && (count($this->prefGroups) == 1)) {
733:             reset($this->prefGroups);
734:             $this->group = key($this->prefGroups);
735:         }
736:     }
737: 
738:     /**
739:      * Get the list of viewable preference groups, filtering out suppressed
740:      * groups and groups with no settable prefs.
741:      *
742:      * @return array  The filtered prefGroups array.
743:      */
744:     protected function _getPrefGroups()
745:     {
746:         $out = array();
747: 
748:         foreach (array_diff(array_keys($this->prefGroups), $this->suppressGroups) as $val) {
749:             if ($this->groupIsEditable($val)) {
750:                 $out[$val] = $this->prefGroups[$val];
751:             }
752:         }
753: 
754:         return $out;
755:     }
756: 
757:     /**
758:      * Adds Horde base identities prefs to preference list.
759:      *
760:      * @param array $pref_list  Preference list.
761:      *
762:      * @return array  The preference list with the Horde preferences added, if
763:      *                needed. These prefs are also added to $this->prefs.
764:      */
765:     protected function _addHordeIdentitiesPrefs($pref_list)
766:     {
767:         if ($this->app != 'horde') {
768:             try {
769:                 $res = $this->_loadPrefs('horde', true);
770:                 foreach ($res['prefGroups'] as $pgroup) {
771:                     if (isset($pgroup['type']) &&
772:                         ($pgroup['type'] == 'identities')) {
773:                         foreach ($pgroup['members'] as $key => $member) {
774:                             if (!$GLOBALS['prefs']->isLocked($member)) {
775:                                 $this->prefs[$member] = $res['_prefs'][$member];
776:                             } else {
777:                                 unset($pgroup['members'][$key]);
778:                             }
779:                         }
780:                         $pref_list = array_merge($pgroup['members'], $pref_list);
781:                     }
782:                 }
783:             } catch (Horde_Exception $e) {}
784:         }
785: 
786:         return $pref_list;
787:     }
788: 
789:     /**
790:      * Output the identities page header entries (default identity,
791:      * identity selection, and identity deletion).
792:      *
793:      * @param array $members  The list of prefs to display on this page.
794:      *
795:      * @return string  HTML output.
796:      */
797:     protected function _identityHeader($members)
798:     {
799:         $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create(null, $this->app);
800:         $default_identity = $identity->getDefault();
801: 
802:         $t = $GLOBALS['injector']->createInstance('Horde_Template');
803:         $t->setOption('gettext', true);
804: 
805:         if ($GLOBALS['prefs']->isLocked('default_identity')) {
806:             $t->set('default_identity', intval($default_identity));
807:             $identities = array($default_identity);
808:         } else {
809:             $t->set('defaultid', Horde_Core_Translation::t("Your default identity:"));
810:             $t->set('label', Horde::label('identity', Horde_Core_Translation::t("Select the identity you want to change:")));
811:             $identities = $identity->getAll('id');
812:         }
813: 
814:         $entry = $js = array();
815:         foreach ($identities as $key => $val) {
816:             $entry[] = array(
817:                 'i' => $key,
818:                 'label' => htmlspecialchars($val),
819:                 'sel' => ($key == $default_identity)
820:             );
821: 
822:             $tmp = array();
823:             foreach ($members as $member) {
824:                 $val = $identity->getValue($member, $key);
825:                 switch ($this->prefs[$member]['type']) {
826:                 case 'checkbox':
827:                 case 'number':
828:                     $val2 = intval($val);
829:                     break;
830: 
831:                 case 'textarea':
832:                     if (is_array($val)) {
833:                         $val = implode("\n", $val);
834:                     }
835:                     // Fall-through
836: 
837:                 default:
838:                     $val2 = $val;
839:                 }
840: 
841:                 // [0] = pref name
842:                 // [1] = pref type
843:                 // [2] = pref value
844:                 $tmp[] = array(
845:                     $member,
846:                     $this->prefs[$member]['type'],
847:                     $val2
848:                 );
849:             }
850:             $js[] = $tmp;
851:         }
852:         $t->set('entry', $entry);
853: 
854:         Horde::addInlineScript(array(
855:             'HordeIdentitySelect.identities = ' . Horde_Serialize::serialize($js, Horde_Serialize::JSON)
856:         ));
857: 
858:         return $t->fetch(HORDE_TEMPLATES . '/prefs/identityselect.html');
859:     }
860: 
861:     /**
862:      * Update identities prefs.
863:      */
864:     protected function _identitiesUpdate()
865:     {
866:         global $conf, $notification, $prefs;
867: 
868:         $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create(null, $this->app);
869: 
870:         if ($this->vars->delete_identity) {
871:             $id = intval($this->vars->identity);
872:             $deleted_identity = $identity->delete($id);
873:             $this->_loadPrefs($this->app);
874:             $notification->push(sprintf(Horde_Core_Translation::t("The identity \"%s\" has been deleted."), $deleted_identity[0]['id']), 'horde.success');
875:             return;
876:         }
877: 
878:         $old_default = $identity->getDefault();
879:         $from_addresses = $identity->getAll('from_addr');
880:         $current_from = $identity->getValue('from_addr');
881:         $id = intval($this->vars->identity);
882: 
883:         if ($prefs->isLocked('default_identity')) {
884:             $id = $old_default;
885:         } else {
886:             $new_default = intval($this->vars->default_identity);
887:             if ($new_default != $old_default) {
888:                 $identity->setDefault($new_default);
889:                 $old_default = $new_default;
890:                 $notification->push(Horde_Core_Translation::t("Your default identity has been changed."), 'horde.success');
891: 
892:                 /* Need to immediately save, since we may short-circuit
893:                  * saving the identities below. */
894:                 $identity->save();
895:             }
896:         }
897: 
898:         if ($id == -2) {
899:             return;
900:         }
901: 
902:         if ($id == -1) {
903:             $id = $identity->add();
904:         }
905: 
906:         $identity->setDefault($id);
907: 
908:         try {
909:             $this->_handleForm($this->_addHordeIdentitiesPrefs($this->getChangeablePrefs($this->group)), $identity);
910:         } catch (Exception $e) {
911:             $notification->push($e, 'horde.error');
912:             return;
913:         }
914: 
915:         $new_from = $identity->getValue('from_addr');
916:         if (!empty($conf['user']['verify_from_addr']) &&
917:             ($current_from != $new_from) &&
918:             !in_array($new_from, $from_addresses)) {
919:             try {
920:                 $identity->verifyIdentity($id, empty($current_from) ? $new_from : $current_from);
921:             } catch (Horde_Exception $e) {
922:                 $notification->push(Horde_Core_Translation::t("The new from address can't be verified, try again later: ") . $e->getMessage(), 'horde.error');
923:                 Horde::logMessage($e, 'ERR');
924:             }
925:         } else {
926:             $identity->setDefault($old_default);
927:             $identity->save();
928:         }
929:     }
930: 
931: }
932: 
API documentation generated by ApiGen