Preferences UI rewrite.
authorMichael M Slusarz <slusarz@curecanti.org>
Thu, 25 Mar 2010 17:55:04 +0000 (11:55 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 6 Apr 2010 20:21:07 +0000 (14:21 -0600)
Goals of the rewrite:
1. Make ALL preference page display across ALL applications handled by a
single point: the horde services preference page. This means moving all
application specifc preference handling to inside of
Horde_Registry_Application functions. NO page, other than
horde/services/prefs.php, should be using the Horde Prefs UI functions
anymore.
2. Move Horde Prefs UI code out of Prefs package and into the Core
package. UI handling is not something that should be handled by a
library (will eventually move other things out of Prefs too, including
Category Management and Identity code, since this is code that overlays
the Prefs driver in a Horde-specific manner)
3. Simplify the prefs UI configuration. Don't require 'shared' or
'locked' entries (default to false) or 'type' entry (default to
'implicit'). Remove some unneeded types (select). Improve documentation.
4. Handle dynamic population of entries and suppression of prefGroups
and specific preferences in Application::prefsInit(). This code confuses
the prefs.php file.
5. Abstract out some common 'special' preference handlers.  For
example, identical addressbook selection code is used in several
applications (imp, kronolith, whups). Move this code to a prefs UI
widgets class so it can be reused.
6. Convert prefs templates to Horde_Template. As always, I know the
arguments against HT, but the simple fact is that is still the only
time-tested method that we used and it does produce a template file that
is easy to edit. Not to mention that the PHP code polluting the old
include files made these files absolutely unreadable and/or
maintainable.
7. Remove credentials code.  It wasn't being used anywhere in the code (I
believe it used to be a hack for IMP-related auth in Horde 3.x, but
shouldn't be needed anymore due to new authentication code).
8. Other improvements that have escaped my mind since I have been
working on this code for several weeks now...

Reasons for the rewrite:
1. The old Prefs UI code was ancient and a mess.  It was a static file
and globals were used all over the place.  New UI code is OO-based and
allows us to pass the object around, making these like suppression of
groups/prefs, hiding buttons, and current state identification much
easier and cleaner.
2. There is a need to redo the UI itself, especially for dynamic
apps, to allow for a different/better preferences experience. Thus, the
UI will eventually be able to be themed based on the current view type
(dynamic, standard, mobile/minimal). To do this, all UI needs to be
controlled from a single source, rather than disparate scripts.
3. Add ability to mark preferences as 'advanced' so they are not shown
by default.  This is prefereable to the current method of 'locking'
advanced prefs.  Admins may very well want users to be able to change a
pref, but they don't want that pref shown to basic users.

161 files changed:
agora/config/prefs.php.dist
agora/lib/Application.php
agora/templates/prefs/avatarselect.inc [deleted file]
ansel/lib/Application.php
fima/lib/Application.php
framework/Core/lib/Horde/Core/Prefs/Ui.php [new file with mode: 0644]
framework/Core/lib/Horde/Core/Prefs/Ui/Widgets.php [new file with mode: 0644]
framework/Core/lib/Horde/Core/Prefs/Utils.php [new file with mode: 0644]
framework/Core/lib/Horde/Registry/Application.php
framework/Core/lib/Horde/Script/Files.php
framework/Core/package.xml
framework/Prefs/lib/Horde/Prefs.php
framework/Prefs/lib/Horde/Prefs/CategoryManager.php
framework/Prefs/lib/Horde/Prefs/Credentials.php [deleted file]
framework/Prefs/lib/Horde/Prefs/File.php
framework/Prefs/lib/Horde/Prefs/Identity.php
framework/Prefs/lib/Horde/Prefs/Imsp.php
framework/Prefs/lib/Horde/Prefs/Kolab.php
framework/Prefs/lib/Horde/Prefs/KolabImap.php
framework/Prefs/lib/Horde/Prefs/Ldap.php
framework/Prefs/lib/Horde/Prefs/Session.php
framework/Prefs/lib/Horde/Prefs/Sql.php
framework/Prefs/lib/Horde/Prefs/Ui.php [deleted file]
framework/Prefs/package.xml
gollem/lib/Application.php
horde/config/hooks.php.dist
horde/config/prefs.php.dist
horde/js/addressbooksprefs.js [new file with mode: 0644]
horde/js/alarmprefs.js [new file with mode: 0644]
horde/js/categoryprefs.js [new file with mode: 0644]
horde/js/rpcprefs.js [new file with mode: 0644]
horde/js/sourceselect.js [new file with mode: 0644]
horde/lib/Application.php
horde/lib/Prefs/Ui.php [new file with mode: 0644]
horde/services/facebook.php
horde/services/portal/rpcsum.php [deleted file]
horde/services/portal/syncml.php [deleted file]
horde/services/prefs.php
horde/services/twitter.php
horde/templates/menu/menu.inc
horde/templates/prefs/addressbooks.html [new file with mode: 0644]
horde/templates/prefs/alarm.html [new file with mode: 0644]
horde/templates/prefs/alarm.inc [deleted file]
horde/templates/prefs/app.html [new file with mode: 0644]
horde/templates/prefs/app.inc [deleted file]
horde/templates/prefs/begin.html [new file with mode: 0644]
horde/templates/prefs/begin.inc [deleted file]
horde/templates/prefs/category.html [new file with mode: 0644]
horde/templates/prefs/categorymanagement.inc [deleted file]
horde/templates/prefs/checkbox.html [new file with mode: 0644]
horde/templates/prefs/checkbox.inc [deleted file]
horde/templates/prefs/credentialsui.inc [deleted file]
horde/templates/prefs/deleteidentity.inc [deleted file]
horde/templates/prefs/end.html [new file with mode: 0644]
horde/templates/prefs/end.inc [deleted file]
horde/templates/prefs/enum.html [new file with mode: 0644]
horde/templates/prefs/enum.inc [deleted file]
horde/templates/prefs/identityselect.html [new file with mode: 0644]
horde/templates/prefs/identityselect.inc [deleted file]
horde/templates/prefs/link.html [new file with mode: 0644]
horde/templates/prefs/link.inc [deleted file]
horde/templates/prefs/multienum.html [new file with mode: 0644]
horde/templates/prefs/multienum.inc [deleted file]
horde/templates/prefs/number.html [new file with mode: 0644]
horde/templates/prefs/number.inc [deleted file]
horde/templates/prefs/overview.html [new file with mode: 0644]
horde/templates/prefs/overview.inc [deleted file]
horde/templates/prefs/password.html [new file with mode: 0644]
horde/templates/prefs/password.inc [deleted file]
horde/templates/prefs/rawhtml.html [new file with mode: 0644]
horde/templates/prefs/rpc.html [new file with mode: 0644]
horde/templates/prefs/select.inc [deleted file]
horde/templates/prefs/source.html [new file with mode: 0644]
horde/templates/prefs/syncml.html [new file with mode: 0644]
horde/templates/prefs/text.html [new file with mode: 0644]
horde/templates/prefs/text.inc [deleted file]
horde/templates/prefs/textarea.html [new file with mode: 0644]
horde/templates/prefs/textarea.inc [deleted file]
horde/templates/rpcsum/rpcsum.inc [deleted file]
horde/templates/syncml/syncml.inc [deleted file]
horde/themes/screen.css
imp/acl.php [deleted file]
imp/config/prefs.php.dist
imp/contacts.php
imp/docs/UPGRADING
imp/filterprefs.php [deleted file]
imp/js/acl.js
imp/js/addressbooksprefs.js [deleted file]
imp/lib/Ajax/Imple/ContactAutoCompleter.php
imp/lib/Application.php
imp/lib/Auth.php
imp/lib/Block/tree_folders.php
imp/lib/Compose.php
imp/lib/Crypt/Pgp.php
imp/lib/Crypt/Smime.php
imp/lib/Imap/Acl.php
imp/lib/Mime/Viewer/Html.php
imp/lib/Prefs/Ui.php [new file with mode: 0644]
imp/pgp.php
imp/smime.php
imp/stationery.php [deleted file]
imp/templates/imp/acl/acl.html [deleted file]
imp/templates/pgp/import_key.html [new file with mode: 0644]
imp/templates/prefs/accounts.html [new file with mode: 0644]
imp/templates/prefs/accountsmanagement.inc [deleted file]
imp/templates/prefs/acl.html [new file with mode: 0644]
imp/templates/prefs/drafts.html [new file with mode: 0644]
imp/templates/prefs/draftsselect.inc [deleted file]
imp/templates/prefs/encrypt.html [new file with mode: 0644]
imp/templates/prefs/encryptselect.inc [deleted file]
imp/templates/prefs/filters/filters.html [deleted file]
imp/templates/prefs/flagmanagement.inc [deleted file]
imp/templates/prefs/flags.html [new file with mode: 0644]
imp/templates/prefs/initialpage.html [new file with mode: 0644]
imp/templates/prefs/initialpageselect.inc [deleted file]
imp/templates/prefs/pgp/import_key.html [deleted file]
imp/templates/prefs/pgp/pgp.html [deleted file]
imp/templates/prefs/pgpprivatekey.html [new file with mode: 0644]
imp/templates/prefs/pgppublickey.html [new file with mode: 0644]
imp/templates/prefs/sentmail.html [new file with mode: 0644]
imp/templates/prefs/sentmailselect.inc [deleted file]
imp/templates/prefs/smime/import_key.html [deleted file]
imp/templates/prefs/smime/smime.html [deleted file]
imp/templates/prefs/smimeprivatekey.html [new file with mode: 0644]
imp/templates/prefs/smimepublickey.html [new file with mode: 0644]
imp/templates/prefs/sound.html [new file with mode: 0644]
imp/templates/prefs/soundselect.inc [deleted file]
imp/templates/prefs/sourceselect.inc [deleted file]
imp/templates/prefs/spam.html [new file with mode: 0644]
imp/templates/prefs/spamselect.inc [deleted file]
imp/templates/prefs/stationery.html [new file with mode: 0644]
imp/templates/prefs/stationery/stationery.html [deleted file]
imp/templates/prefs/trash.html [new file with mode: 0644]
imp/templates/prefs/trashselect.inc [deleted file]
imp/templates/smime/import_key.html [new file with mode: 0644]
imp/themes/screen.css
kronolith/config/prefs.php.dist
kronolith/index.php
kronolith/lib/Application.php
kronolith/templates/prefs/default_alarm_management.inc [deleted file]
kronolith/templates/prefs/defaultalarm.html [new file with mode: 0644]
kronolith/templates/prefs/fb_cals_select.inc [deleted file]
kronolith/templates/prefs/shareselect.inc [deleted file]
kronolith/templates/prefs/sourceselect.inc [deleted file]
kronolith/themes/screen.css
nag/config/prefs.php.dist
nag/lib/Application.php
nag/templates/prefs/defaultduetimeselect.inc [deleted file]
nag/templates/prefs/tasklistselect.inc [deleted file]
turba/config/prefs.php.dist
turba/config/sources.php.dist
turba/js/columnprefs.js [new file with mode: 0644]
turba/lib/Application.php
turba/templates/prefs/addressbookselect.inc [deleted file]
turba/templates/prefs/column.html [new file with mode: 0644]
turba/templates/prefs/columnselect.inc [deleted file]
turba/templates/prefs/imsp_opt.inc [deleted file]
whups/config/prefs.php.dist
whups/lib/Application.php
whups/lib/View.php [changed mode: 0755->0644]
whups/templates/prefs/sourceselect.inc [deleted file]

index 82ad0f2..efe4109 100644 (file)
@@ -10,7 +10,7 @@ if ($GLOBALS['conf']['avatar']['allow_avatars']) {
         'column' => _("My Information"),
         'label' => _("Avatar"),
         'desc' => _("Set the avatar image that is shown with your posts."),
-        'members' => array('avatar_path', 'avatarselect')
+        'members' => array('avatar_path', 'avatar_link')
     );
 }
 
@@ -25,15 +25,20 @@ $prefGroups['display_threads'] = array(
     'column' => _("Display Options"),
     'label' => _("Threads View"),
     'desc' => _("Set your options for the threads view."),
-    'members' => array('threads_sortby', 'threads_sortdir', 'threads_hot', 'threads_per_page')
+    'members' => array(
+        'threads_sortby', 'threads_sortdir', 'threads_hot',
+        'threads_per_page'
+    )
 );
 
 $prefGroups['display_thread'] = array(
     'column' => _("Display Options"),
     'label' => _("Single Thread View"),
     'desc' => _("Set your options for the single thread view."),
-    'members' => array('thread_sortby', 'thread_sortdir', 'thread_view_bodies',
-                       'thread_per_page')
+    'members' => array(
+        'thread_sortby', 'thread_sortdir', 'thread_view_bodies',
+        'thread_per_page'
+    )
 );
 
 $prefGroups['display_message'] = array(
@@ -47,59 +52,67 @@ $prefGroups['display_comments'] = array(
     'column' => _("Display Options"),
     'label' => _("Comments view"),
     'desc' => _("Set your options for the single thread view."),
-    'members' => array('comments_sortby', 'comments_sortdir', 'comments_view_bodies',
-                       'comments_per_page')
+    'members' => array(
+        'comments_sortby', 'comments_sortdir', 'comments_view_bodies',
+        'comments_per_page'
+    )
 );
 
 /* Avatar */
 
 $_prefs['avatar_path'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'text',
     'desc' => _("The location of your avatar image.")
 );
-if ($GLOBALS['conf']['avatar']['allow_avatars'] && $GLOBALS['conf']['avatar']['enable_image_tests']) {
+if ($GLOBALS['conf']['avatar']['allow_avatars'] &&
+   $GLOBALS['conf']['avatar']['enable_image_tests']) {
     $_prefs['avatar_path']['desc'] .= ' ' . sprintf(_("Avatars must be smaller than %s by %s pixels and less than %sKb in size."),
                     $GLOBALS['conf']['avatar']['max_width'],
                     $GLOBALS['conf']['avatar']['max_height'],
                     $GLOBALS['conf']['avatar']['max_size']);
 }
 
-$_prefs['avatarselect'] = array('type' => 'special');
+$_prefs['avatar_link'] = array(
+    'type' => 'rawhtml',
+    'url' => '<p>' . _("Choose from a gallery of avatars:") . ' <input class="button" type="button" value="' . _("Click to Show Gallery") . '" onclick="' . Horde::popupJs(Horde::applicationUrl('avatars/gallery.php'), array('height' => 320, 'width' => 320)) . '" /></p>'
+);
 
 /* Forums */
 
 $_prefs['forums_sortby'] = array(
     'value' => 'forum_name',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('forum_name' => _("Forum"),
-                    'message_count' => _("Messages"),
-                    'message_subject' => _("Last Message"),
-                    'message_author' => _("Posted by"),
-                    'message_date' => _("Date")),
+    'enum' => array(
+        'forum_name' => _("Forum"),
+        'message_count' => _("Messages"),
+        'message_subject' => _("Last Message"),
+        'message_author' => _("Posted by"),
+        'message_date' => _("Date")
+    ),
     'desc' => _("Default forums view sort:")
 );
 
 $_prefs['forums_sortdir'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("Ascending"),
-                    1 => _("Descending")),
+    'enum' => array(
+        0 => _("Ascending"),
+        1 => _("Descending")
+    ),
     'desc' => _("Default sorting direction:")
 );
 
 $_prefs['forums_per_page'] = array(
     'value' => 20,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(5 => 5, 10 => 10, 15 => 15, 20 => 20, 25 => 25),
+    'enum' => array(
+        5 => 5,
+        10 => 10,
+        15 => 15,
+        20 => 20,
+        25 => 25
+    ),
     'desc' => _("Number of forums to display on each page")
 );
 
@@ -107,42 +120,44 @@ $_prefs['forums_per_page'] = array(
 
 $_prefs['threads_sortby'] = array(
     'value' => 'message_modifystamp',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('message_thread' => _("Thread"),
-                    'message_subject' => _("Subject"),
-                    'message_author' => _("Posted by"),
-                    'message_seq' => _("Posts"),
-                    'message_timestamp' => _("Date"),
-                    'message_modifystamp' => _("Last post")),
+    'enum' => array(
+        'message_thread' => _("Thread"),
+        'message_subject' => _("Subject"),
+        'message_author' => _("Posted by"),
+        'message_seq' => _("Posts"),
+        'message_timestamp' => _("Date"),
+        'message_modifystamp' => _("Last post")
+    ),
     'desc' => _("Default threads view sort:")
 );
 
 $_prefs['threads_sortdir'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("Ascending"),
-                    1 => _("Descending")),
+    'enum' => array(
+        0 => _("Ascending"),
+        1 => _("Descending")
+   ),
     'desc' => _("Default sorting direction:")
 );
 
 $_prefs['threads_hot'] = array(
     'value' => 20,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Number of views in 24hrs to trigger a 'hot-thread':")
 );
 
 $_prefs['threads_per_page'] = array(
     'value' => 10,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(5 => 5, 10 => 10, 15 => 15, 20 => 20, 25 => 25),
+    'enum' => array(
+        5 => 5,
+        10 => 10,
+        15 => 15,
+        20 => 20,
+        25 => 25
+    ),
     'desc' => _("Number of messages to display on each page")
 );
 
@@ -150,78 +165,74 @@ $_prefs['threads_per_page'] = array(
 
 $_prefs['thread_sortby'] = array(
     'value' => 'message_timestamp',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('message_thread' => _("Thread"),
-                    'message_subject' => _("Subject"),
-                    'message_author' => _("Posted by"),
-                    'message_timestamp' => _("Date")),
+    'enum' => array(
+        'message_thread' => _("Thread"),
+        'message_subject' => _("Subject"),
+        'message_author' => _("Posted by"),
+        'message_timestamp' => _("Date")
+    ),
     'desc' => _("Default thread view sort:")
 );
 
 $_prefs['thread_sortdir'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("Ascending"),
-                    1 => _("Descending")),
+    'enum' => array(
+        0 => _("Ascending"),
+        1 => _("Descending")
+    ),
     'desc' => _("Default sorting direction:")
 );
 
 $_prefs['thread_view_bodies'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("No"),
-                    1 => _("Yes"),
-                    2 => _("Yes, and don't thread them")),
+    'enum' => array(
+        0 => _("No"),
+        1 => _("Yes"),
+        2 => _("Yes, and don't thread them")
+    ),
     'desc' => _("Display full message bodies in the thread list view?")
 );
 
 $_prefs['thread_per_page'] = array(
     'value' => 10,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(5 => 5, 10 => 10, 15 => 15, 20 => 20, 25 => 25),
+    'enum' => array(
+        5 => 5,
+        10 => 10,
+        15 => 15,
+        20 => 20,
+        25 => 25
+    ),
     'desc' => _("Number of message to display on each page")
 );
 
 $_prefs['message_emoticons'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("No graphical emoticons"),
-                    1 => _("Show graphical emoticons")),
+    'enum' => array(
+        0 => _("No graphical emoticons"),
+        1 => _("Show graphical emoticons")
+   ),
     'desc' => _("Display graphical emoticons?")
 );
 
 $_prefs['forums_block_display'] = array(
-    'value' => 0,
-    'type' => 'implicit'
+    'value' => 0
 );
 
 $_prefs['threads_block_display'] = array(
-    'value' => 0,
-    'type' => 'implicit'
+    'value' => 0
 );
 
 $_prefs['moderate_sortby'] = array(
-    'value' => 'message_id',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => 'message_id'
 );
 
 $_prefs['moderate_sortdir'] = array(
-    'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => 0
 );
 
 
@@ -229,40 +240,44 @@ $_prefs['moderate_sortdir'] = array(
 
 $_prefs['comments_view_bodies'] = array(
     'value' => 2,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(2 => _("Flat"),
-                    1 => _("Thread")),
+    'enum' => array(
+        2 => _("Flat"),
+        1 => _("Thread")
+    ),
     'desc' => _("Display full message bodies in the comments view?")
 );
 
 $_prefs['comments_sortby'] = array(
     'value' => 'message_timestamp',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('message_subject' => _("Subject"),
-                    'message_author' => _("Posted by"),
-                    'message_timestamp' => _("Date")),
+    'enum' => array(
+        'message_subject' => _("Subject"),
+        'message_author' => _("Posted by"),
+        'message_timestamp' => _("Date")
+    ),
     'desc' => _("Default comments view sort:")
 );
 
 $_prefs['comments_sortdir'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("Ascending"),
-                    1 => _("Descending")),
+    'enum' => array(
+        0 => _("Ascending"),
+        1 => _("Descending")
+    ),
     'desc' => _("Default sorting direction:")
 );
 
 $_prefs['comments_per_page'] = array(
     'value' => 20,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(5 => 5, 10 => 10, 15 => 15, 20 => 20, 25 => 25),
+    'enum' => array(
+        5 => 5,
+        10 => 10,
+        15 => 15,
+        20 => 20,
+        25 => 25
+    ),
     'desc' => _("Number of messages to display on each page")
 );
index 92dbf84..a99324d 100644 (file)
@@ -84,6 +84,50 @@ class Agora_Application extends Horde_Registry_Application
     }
 
     /**
+     * Code to run on init when viewing prefs for this application.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    public function prefsInit($ui)
+    {
+        switch ($ui->group) {
+        case 'display_avatar':
+            $vfs = Agora::getVFS();
+            if (!($vfs instanceof PEAR_Error) &&
+                $GLOBALS['conf']['avatar']['enable_gallery'] &&
+                $vfs->isFolder(Agora::AVATAR_PATH, 'gallery')) {
+                Horde::addScriptFile('popup.js', 'horde', true);
+            } else {
+                $suppress[] = 'avatar_link'
+            }
+            break;
+        }
+
+        /* Hide appropriate prefGroups. */
+        if (!$GLOBALS['conf']['avatar']['allow_avatars']) {
+            $ui->suppressGroups[] = 'display_avatar';
+        }
+    }
+
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    public function prefsSpecial($ui, $item)
+    {
+        switch ($item) {
+        case 'avatarselect':
+            return $this->_accountsManagement($ui);
+        }
+
+        return '';
+    }
+
+    /**
      * Generate the menu to use on the prefs page.
      *
      * @return Horde_Menu  A Horde_Menu object.
diff --git a/agora/templates/prefs/avatarselect.inc b/agora/templates/prefs/avatarselect.inc
deleted file mode 100644 (file)
index 22157e0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-Horde::addScriptFile('popup.js', 'horde', true);
-if ($vfs = Agora::getVFS() instanceof PEAR_Error) {
-    Horde::fatal($vfs, __FILE__, __LINE__);
-}
-if ($GLOBALS['conf']['avatar']['enable_gallery'] && $vfs->isFolder(Agora::AVATAR_PATH, 'gallery')): ?>
-<p>
- <?php echo _("Choose from a gallery of avatars: ") ?><input class="button" type="button" value="Click to Show Gallery" onclick="popup('<?php echo Horde::applicationUrl('avatars/gallery.php') ?>', 320, 320);">
-</p>
-<?php endif; ?>
index f63c150..5a50395 100644 (file)
@@ -97,32 +97,28 @@ class Ansel_Application extends Horde_Registry_Application
     /**
      * Special preferences handling on update.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
      * @return boolean  True if preference was updated.
      */
-    public function prefsSpecial($item, $updated)
+    public function prefsSpecialUpdate($ui, $item)
     {
         switch ($item) {
         case 'default_category_select':
-            $default_category = Horde_Util::getFormData('default_category_select');
-            if (!is_null($default_category)) {
-                $GLOBALS['prefs']->setValue('default_category', $default_category);
+            if (isset($ui->vars->default_category_select)) {
+                $GLOBALS['prefs']->setValue('default_category', $ui->vars->default_category_select);
                 return true;
             }
             break;
 
         case 'default_gallerystyle_select':
-            $default_style = Horde_Util::getFormData('default_gallerystyle_select');
-            if (!is_null($default_style)) {
-                $GLOBALS['prefs']->setValue('default_gallerystyle', $default_style);
+            if (isset($ui->vars->default_gallerystyle_select)) {
+                $GLOBALS['prefs']->setValue('default_gallerystyle', $ui->vars->default_gallerystyle_select);
                 return true;
             }
             break;
         }
-
-        return $updated;
     }
 
     /**
index fb9628b..f998571 100644 (file)
@@ -6,38 +6,33 @@ class Fima_Application extends Horde_Regsitry_Application
     /**
      * Special preferences handling on update.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
      * @return boolean  True if preference was updated.
      */
-    public function prefsSpecial($item, $updated)
+    public function prefsSpecialUpdate($ui, $item)
     {
         switch ($item) {
         case 'ledgerselect':
-            $active_ledger = Horde_Util::getFormData('active_ledger');
-            if (!is_null($active_ledger)) {
+            if (isset($ui->vars->active_ledger)) {
                 $ledgers = Fima::listLedgers();
                 if (is_array($ledgers) &&
-                    array_key_exists($active_ledger, $ledgers)) {
-                    $GLOBALS['prefs']->setValue('active_ledger', $active_ledger);
+                    array_key_exists($ui->vars->active_ledger, $ledgers)) {
+                    $GLOBALS['prefs']->setValue('active_ledger', $ui->vars->active_ledger);
                     return true;
                 }
             }
             break;
 
         case 'closedperiodselect':
-            $period = Horde_Util::getFormData('closedperiod');
-            if ((int)$period['year'] > 0 && (int)$period['month'] > 0) {
-                $period = mktime(0, 0, 0, $period['month'] + 1, 0, $period['year']);
-            } else {
-                $period = 0;
-            }
+            $period = $ui->vars->closedperiod;
+            $period = ((int)$period['year'] > 0 && (int)$period['month'] > 0)
+                ? mktime(0, 0, 0, $period['month'] + 1, 0, $period['year'])
+                : 0;
             $GLOBALS['prefs']->setValue('closed_period', $period);
             return true;
         }
-
-        return $updated;
     }
 
     /**
diff --git a/framework/Core/lib/Horde/Core/Prefs/Ui.php b/framework/Core/lib/Horde/Core/Prefs/Ui.php
new file mode 100644 (file)
index 0000000..82024c0
--- /dev/null
@@ -0,0 +1,711 @@
+<?php
+/**
+ * Class for generating/processing the preferences UI.
+ *
+ * See Horde_Registry_Application:: for a summary of the API callbacks that
+ * are available.
+ *
+ * Copyright 2001-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @author   Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package  Core
+ */
+class Horde_Core_Prefs_Ui
+{
+    /**
+     * Preferences groups.
+     *
+     * @var array
+     */
+    public $prefGroups = array();
+
+    /**
+     * Preferences.
+     *
+     * @var array
+     */
+    public $prefs = array();
+
+    /**
+     * Data overrides (for 'enum' and 'multienum' types).
+     *
+     * @var array
+     */
+    public $override = array();
+
+    /**
+     * Suppressed preference entries.
+     *
+     * @var array
+     */
+    public $suppress = array();
+
+    /**
+     * Suppressed prefGroup entries.
+     *
+     * @var array
+     */
+    public $suppressGroups = array();
+
+    /**
+     * Current application.
+     *
+     * @var string
+     */
+    public $app;
+
+    /**
+     * Current preferences group.
+     *
+     * @var string
+     */
+    public $group;
+
+    /**
+     * Form variables for this page load.
+     *
+     * @var Horde_Variables
+     */
+    public $vars;
+
+    /**
+     * If set, suppresses display of the buttons.
+     *
+     * @var boolean
+     */
+    public $nobuttons = false;
+
+    /**
+     * Constructor.
+     *
+     * @param Horde_Variables $vars  Form variables.
+     */
+    public function __construct($vars)
+    {
+        $this->app = isset($vars->app)
+            ? $vars->app
+            : $this->getDefaultApp();
+        $this->group = $vars->group;
+        $this->vars = $vars;
+
+        /* Load the application's base environment. */
+        $GLOBALS['registry']->pushApp($this->app);
+
+        /* Load preferences. */
+        $this->_loadPrefs($this->app);
+    }
+
+    /**
+     * Hide the menu display for prefs UI pages during this session?
+     *
+     * @param boolean $hide  If true, hides the menu.
+     */
+    static public function hideMenu($hide)
+    {
+        $_SESSION['horde_prefs']['nomenu'] = $hide;
+    }
+
+    /**
+     * Determine whether or not a preferences group is editable.
+     *
+     * @param string $group  The preferences group to check.
+     *
+     * @return boolean  Whether or not the group is editable.
+     */
+    public function groupIsEditable($group)
+    {
+        return (bool)count($this->getChangeablePrefs($group));
+    }
+
+    /**
+     * Returns the list of changeable prefs for a group.
+     *
+     * @param string $group      The preferences group to check.
+     * @param boolean $implicit  Don't add to list if marked as implict?
+     *
+     * @return array  The list of changeable prefs.
+     */
+    public function getChangeablePrefs($group, $implicit = false)
+    {
+        $prefs = array();
+
+        foreach ($this->prefGroups[$group]['members'] as $pref) {
+            if (!$GLOBALS['prefs']->isLocked($pref) &&
+                !in_array($pref, $this->suppress) &&
+                (!$implicit ||
+                 (!empty($this->prefs[$pref]['type']) &&
+                  ($this->prefs[$pref]['type'] != 'implicit')))) {
+                $prefs[] = $pref;
+            }
+        }
+
+        return $prefs;
+    }
+
+    /**
+     * Handle a preferences form submission if there is one, updating
+     * any preferences which have been changed.
+     *
+     * @return boolean  Whether preferences have been updated.
+     */
+    public function handleForm()
+    {
+        if (!$this->group || !$this->groupIsEditable($this->group)) {
+            return false;
+        }
+
+        if (isset($this->vars->prefs_return)) {
+            $this->group = $this->vars->actionID = '';
+            return false;
+        }
+
+        switch ($this->vars->actionID) {
+        case 'update_prefs':
+            return $this->_handleForm($this->getChangeablePrefs($this->group));
+
+        case 'update_special':
+            $special = array();
+            foreach ($this->getChangeablePrefs($this->group, true) as $pref) {
+                if ($this->prefs[$pref]['type'] == 'special') {
+                    $special[] = $pref;
+                }
+            }
+            return $this->_handleForm($special);
+        }
+
+        return false;
+    }
+
+    /*
+     * Handle a preferences form submission if there is one, updating
+     * any preferences which have been changed.
+     *
+     * @param array $preflist  The list of preferences to process.
+     *
+     * @return boolean  Whether preferences have been updated.
+     */
+    protected function _handleForm($preflist)
+    {
+        global $notification, $prefs, $registry;
+
+        $updated = false;
+
+        /* Run through the action handlers */
+        foreach ($preflist as $pref) {
+            switch ($this->prefs[$pref]['type']) {
+            case 'alarm':
+                $methods = Horde_Alarm::notificationMethods();
+                $val = (isset($this->vars->$pref) && is_array($this->vars->$pref))
+                    ? $this->vars->$pref
+                    : array();
+                $value = array();
+
+                foreach ($val as $method) {
+                    $value[$method] = array();
+                    if (!empty($methods[$method])) {
+                        foreach (array_keys($methods[$method]) as $param) {
+                            $value[$method][$param] = $this->vars->get($pref . '_' . $param, '');
+                            if (is_array($methods[$method][$param]) &&
+                                $methods[$method][$param]['required'] &&
+                                ($value[$method][$param] === '')) {
+                                $notification->push(sprintf(_("You must provide a setting for \"%s\"."), $methods[$method][$param]['desc']), 'horde.error');
+                                break 3;
+                            }
+                        }
+                    }
+                }
+
+                $updated |= $prefs->setValue($pref, serialize($value));
+                break;
+
+            case 'checkbox':
+                $updated |= $prefs->setValue($pref, intval(isset($this->vars->$pref)));
+                break;
+
+            case 'enum':
+                if (isset($this->prefs[$pref]['enum'][$this->vars->$pref])) {
+                    $updated |= $prefs->setValue($pref, $this->vars->$pref);
+                } else {
+                    $notification->push(_("An illegal value was specified."), 'horde.error');
+                }
+                break;
+
+            case 'multienum':
+                $set = array();
+
+                if (is_array($this->vars->$pref)) {
+                    foreach ($this->vars->$pref as $val) {
+                        if (isset($this->prefs[$pref]['enum'][$val])) {
+                            $set[] = $val;
+                        } else {
+                            $notification->push(_("An illegal value was specified."), 'horde.error');
+                            break 2;
+                        }
+                    }
+                }
+
+                $updated |= $prefs->setValue($pref, @serialize($set));
+                break;
+
+            case 'number':
+                $num = $this->vars->$pref;
+                if ((string)(double)$num !== $num) {
+                    $notification->push(_("This value must be a number."), 'horde.error');
+                } elseif (empty($num)) {
+                    $notification->push(_("This number must be non-zero."), 'horde.error');
+                } else {
+                    $updated |= $prefs->setValue($pref, $num);
+                }
+                break;
+
+            case 'password':
+            case 'text':
+            case 'textarea':
+                $updated |= $prefs->setValue($pref, $this->vars->$pref);
+                break;
+
+
+            case 'special':
+                /* Code for special elements written specifically for each
+                 * application. */
+                if ($registry->hasAppMethod($this->app, 'prefsSpecialUpdate')) {
+                    $updated = $updated | (bool)$registry->callAppMethod($this->app, 'prefsSpecialUpdate', array('args' => array($this, $pref)));
+                }
+                break;
+            }
+        }
+
+        if ($updated) {
+            if ($registry->hasAppMethod($this->app, 'prefsCallback')) {
+                $registry->callAppMethod($this->app, 'prefsCallback', array('args' => array($this)));
+            }
+
+            if ($prefs instanceof Horde_Prefs_Session) {
+                $notification->push(_("Your options have been updated for the duration of this session."), 'horde.success');
+            } else {
+                $notification->push(_("Your options have been updated."), 'horde.success');
+            }
+
+            $this->_loadPrefs($this->app);
+        }
+
+        return $updated;
+    }
+
+    /**
+     * Returns a self URL to the current page.
+     *
+     * @param array $options  Additional options:
+     * <pre>
+     * 'special' - (boolean) If set, will trigger special action update
+     *             processing when the URL is loaded.
+     * </pre>
+     *
+     * @return Horde_Url  The URL object.
+     */
+    public function selfUrl($options = array())
+    {
+        $url = Horde::getServiceLink('options', $this->app);
+        if ($this->group) {
+            $url->add('group', $this->group);
+        }
+        if (!empty($options['special'])) {
+            $url->add('actionID', 'update_special');
+        }
+        return $url;
+    }
+
+    /**
+     * Generate the UI for the preferences interface, either for a
+     * specific group, or the group selection interface.
+     */
+    public function generateUI()
+    {
+        global $notification, $prefs, $registry;
+
+        $columns = $pref_list = array();
+
+        /* Run app-specific init code. */
+        if ($registry->hasAppMethod($this->app, 'prefsInit')) {
+            $registry->callAppMethod($this->app, 'prefsInit', array('args' => array($this)));
+        }
+
+        $prefgroups = $this->_getPrefGroups();
+
+        if ($this->group) {
+            $pref_list = $this->getChangeablePrefs($this->group, true);
+        } else {
+            foreach ($prefgroups as $key => $val) {
+                $columns[$val['column']][$key] = $val;
+            }
+        }
+
+        if (empty($columns) && empty($pref_list)) {
+            $notification->push(_("There are no options available."), 'horde.message');
+            $this->nobuttons = true;
+        }
+
+        $options_link = Horde::getServiceLink('options');
+        $h_templates = $registry->get('templates', 'horde');
+
+        $base = $GLOBALS['injector']->createInstance('Horde_Template');
+        $base->setOption('gettext', true);
+
+        /* Need to buffer output - it is possible that 'special' types can
+         * do things like add javascript to the page output. This should all
+         * be combined and served in the page HEAD. */
+        ob_start();
+
+        if ($this->group) {
+            foreach ($pref_list as $pref) {
+                if ($this->prefs[$pref]['type'] == 'special') {
+                    if ($registry->hasAppMethod($this->app, 'prefsSpecial')) {
+                        echo $registry->callAppMethod($this->app, 'prefsSpecial', array('args' => array($this, $pref)));
+                    }
+
+                    continue;
+                }
+
+                $t = clone $base;
+                if (isset($this->prefs[$pref]['desc'])) {
+                    $t->set('desc', Horde::label($pref, $this->prefs[$pref]['desc']));
+                }
+                $t->set('helplink', empty($this->prefs[$pref]['help']) ? null : Horde_Help::link(empty($this->prefs[$pref]['shared']) ? $this->app : 'horde', $this->prefs[$pref]['help']));
+                $t->set('pref', htmlspecialchars($pref));
+
+                $type = $this->prefs[$pref]['type'];
+                switch ($type) {
+                case 'alarm':
+                    Horde::addScriptFile('alarmprefs.js', 'horde');
+                    Horde::addInlineScript(array(
+                        'HordeAlarmPrefs.pref = ' . Horde_Serialize::serialize($pref, Horde_Serialize::JSON)
+                    ));
+
+                    $alarm_pref = unserialize($prefs->getValue($pref));
+                    $selected = array_keys($alarm_pref);
+
+                    $param_list = $select_list = array();
+                    foreach (Horde_Alarm::notificationMethods() as $method => $params) {
+                        $select_list[] = array(
+                            'l' => $params['__desc'],
+                            's' => in_array($method, $selected),
+                            'v' => $method
+                        );
+
+                        if (count($params > 1)) {
+                            $tmp = array(
+                                'method' => $method,
+                                'param' => array()
+                            );
+
+                            foreach ($params as $name => $param) {
+                                if (substr($name, 0, 2) == '__') {
+                                    continue;
+                                }
+
+                                switch ($param['type']) {
+                                case 'text':
+                                    $tmp['param'][] = array(
+                                        'label' => Horde::label($pref . '_' . $name, $param['desc']),
+                                        'name' => $pref . '_' . $name,
+                                        'text' => true,
+                                        'value' => empty($alarm_pref[$method][$name]) ? '' : htmlspecialchars($alarm_pref[$method][$name])
+                                    );
+                                    break;
+
+                                case 'bool':
+                                    $tmp['param'][] = array(
+                                        'bool' => true,
+                                        'checked' => !empty($alarm_pref[$method][$name]),
+                                        'label' => Horde::label($pref . '_' . $name, $param['desc']),
+                                        'name' => $pref . '_' . $name
+                                    );
+                                    break;
+
+                                case 'sound':
+                                    $current_sound = empty($alarm_pref[$method][$name])
+                                        ? ''
+                                        : $alarm_pref[$method][$name];
+                                    $sounds = array();
+                                    foreach (Horde_Themes::soundList() as $key => $val) {
+                                        $sounds[] = array(
+                                            'c' => ($current_sound == $key),
+                                            'uri' => htmlspecialchars($val->uri),
+                                            'val' => htmlspecialchars($key)
+                                        );
+                                    }
+
+                                    $tmp['param'][] = array(
+                                        'sound' => true,
+                                        'checked' => !$current_sound,
+                                        'name' => $pref . '_' . $name
+                                    );
+                                    break;
+                                }
+                            }
+
+                            $param_list[] = $tmp;
+                        }
+                    }
+                    $t->set('param_list', $param_list);
+                    $t->set('select_list', $select_list);
+                    break;
+
+                case 'checkbox':
+                    $t->set('checked', $prefs->getValue($pref));
+                    break;
+
+                case 'enum':
+                    $enum = isset($this->override[$pref])
+                        ? $this->override[$pref]
+                        : $this->prefs[$pref]['enum'];
+                    $esc = !empty($this->prefs[$pref]['escaped']);
+                    $curval = $prefs->getValue($pref);
+
+                    $tmp = array();
+                    foreach ($enum as $key => $val) {
+                        $tmp[] = array(
+                            'l' => $esc ? $val : htmlspecialchars($val),
+                            's' => ($curval == $key),
+                            'v' => $esc ? $key : htmlspecialchars($key)
+                        );
+                    }
+                    $t->set('enum', $tmp);
+                    break;
+
+                case 'prefslink':
+                    $url = $this->selfUrl()->add('group', $this->prefs[$pref]['group']);
+                    if (!empty($this->prefs[$pref]['app'])) {
+                        $url->add('app', $this->prefs[$pref]['app']);
+                    }
+                    $this->prefs[$pref]['url'] = $url;
+                    $type = 'link';
+                    // Fall through to 'link'
+
+                case 'link':
+                    if (isset($this->prefs[$pref]['img'])) {
+                        $t->set('img', Horde::img($this->prefs[$pref]['img'], $this->prefs[$pref]['desc'], array('class' => 'prefsLinkImg')));
+                    }
+                    $t->set('url', isset($this->prefs[$pref]['url']) ? Horde::applicationUrl($this->prefs[$pref]['url']) : $this->prefs[$pref]['xurl']);
+                    if (isset($this->prefs[$pref]['target'])) {
+                        $t->set('target', htmlspecialchars($this->prefs[$pref]['target']));
+                    }
+                    break;
+
+                case 'multienum':
+                    $enum = isset($this->override[$pref])
+                        ? $this->override[$pref]
+                        : $this->prefs[$pref]['enum'];
+                    $esc = !empty($this->prefs[$pref]['escaped']);
+                    if (!$selected = @unserialize($prefs->getValue($pref))) {
+                        $selected = array();
+                    }
+
+                    $tmp = array();
+                    foreach ($enum as $key => $val) {
+                        $tmp[] = array(
+                            'l' => $esc ? $val : htmlspecialchars($val),
+                            's' => in_array($key, $selected),
+                            'v' => $esc ? $key : htmlspecialchars($key)
+                        );
+                    }
+                    $t->set('enum', $tmp);
+
+                    $t->set('size', min(4, count($enum)));
+                    break;
+
+                case 'number':
+                    $t->set('val', htmlspecialchars(intval($prefs->getValue($pref))));
+                    break;
+
+                case 'password':
+                case 'text':
+                case 'textarea':
+                    $t->set('val', htmlspecialchars($prefs->getValue($pref)));
+                    break;
+
+                case 'rawhtml':
+                    $t->set('html', $this->prefs[$pref]['value']);
+                    break;
+                }
+
+                echo $t->fetch(HORDE_TEMPLATES . '/prefs/' . $type . '.html');
+            }
+
+            $t = clone $base;
+            $t->set('buttons', !$this->nobuttons);
+            $t->set('prefgroups', count($prefgroups) > 1);
+            echo $t->fetch($h_templates . '/prefs/end.html');
+        } elseif (!empty($columns)) {
+            $t = clone $base;
+            $span = round(100 / count($columns));
+
+            $cols = array();
+            foreach ($columns as $key => $column) {
+                $tmp = array(
+                    'groups' => array(),
+                    'hdr' => htmlspecialchars($key),
+                    'width' => $span - 1
+                );
+
+                foreach ($column as $group => $gvals) {
+                    if ($this->groupIsEditable($group)) {
+                        $tmp['groups'][] = array(
+                            'desc' => htmlspecialchars($gvals['desc']),
+                            'link' => Horde::widget($options_link->copy()->add(array('app' => $this->app, 'group' => $group)), $gvals['label'], '', '', '', $gvals['label'])
+                        );
+                    }
+                }
+                $cols[] = $tmp;
+            }
+            $t->set('columns', $cols);
+
+            echo $t->fetch($h_templates . '/prefs/overview.html');
+        }
+
+        $content = ob_get_clean();
+
+        $title = _("User Options");
+
+        /* Get the menu output before we start to output the page.
+         * Again, this will catch any javascript inserted into the page. */
+        if (empty($_SESSION['horde_prefs']['nomenu'])) {
+            if ($registry->hasAppMethod($this->app, 'prefsMenu')) {
+                $menu = $registry->callAppMethod($this->app, 'prefsMenu', array('args' => array($this)));
+            }
+        }
+
+        /* Get list of accessible applications. */
+        $apps = array();
+        foreach ($registry->listApps() as $app) {
+            // Make sure the app is installed and has a prefs file.
+            if (file_exists($registry->get('fileroot', $app) . '/config/prefs.php')) {
+                $apps[$app] = $registry->get('name', $app);
+            }
+        }
+        asort($apps);
+
+        /* Ouptut screen. */
+        $GLOBALS['bodyId'] = 'services_prefs';
+        require $h_templates . '/common-header.inc';
+
+        if (empty($_SESSION['horde_prefs']['nomenu'])) {
+            require $h_templates . '/menu/menu.inc';
+        }
+
+        $notification->notify(array('listeners' => 'status'));
+
+        $base_ui = clone $base;
+        $base_ui->set('action', $options_link);
+        $base_ui->set('forminput', Horde_Util::formInput());
+
+        /* Show the current application and a form for switching
+         * applications. */
+        $t = clone $base_ui;
+        $t->set('horde', !empty($apps['horde']));
+        unset($apps['horde'], $apps[$this->app]);
+        $tmp = array();
+        foreach ($apps as $key => $val) {
+            $tmp[] = array(
+                'l' => htmlspecialchars($val),
+                'v' => htmlspecialchars($key)
+            );
+        }
+        $t->set('apps', $tmp);
+        $t->set('header', htmlspecialchars(($this->app == 'horde') ? _("Global Options") : sprintf(_("Options for %s"), $registry->get('name', $this->app))));
+        echo $t->fetch($h_templates . '/prefs/app.html');
+
+        /* Generate navigation header. */
+        if ($this->group) {
+            $t = clone $base_ui;
+            $t->set('app', htmlspecialchars($this->app));
+            $t->set('group', htmlspecialchars($this->group));
+            $t->set('label', htmlspecialchars($this->prefGroups[$this->group]['label']));
+
+            // Search for previous and next groups.
+            if (count($prefgroups) > 1) {
+                $prefgroups = array_keys($prefgroups);
+                $key = array_search($this->group, $prefgroups);
+                $previous = isset($prefgroups[$key - 1])
+                    ? $prefgroups[$key - 1]
+                    : end($prefgroups);
+                $next = isset($prefgroups[$key + 1])
+                    ? $prefgroups[$key + 1]
+                    : reset($prefgroups);
+                $prefs_url = $this->selfUrl();
+
+                $t->set('prev', $prefs_url->copy()->add('group', $previous));
+                $t->set('prevlabel', htmlspecialchars($this->prefGroups[$previous]['label']));
+                $t->set('next', $prefs_url->copy()->add('group', $next));
+                $t->set('nextlabel', htmlspecialchars($this->prefGroups[$next]['label']));
+            }
+
+            echo $t->fetch($h_templates . '/prefs/begin.html');
+        }
+
+        echo $content;
+
+        require $h_templates . '/common-footer.inc';
+    }
+
+    /**
+     * Get the default application to show preferences for. Defaults
+     * to 'horde'.
+     *
+     * @return string  The default application.
+     */
+    public function getDefaultApp()
+    {
+        $applications = $GLOBALS['registry']->listApps(null, true, Horde_Perms::READ);
+        return isset($applications['horde'])
+            ? 'horde'
+            : array_shift($applications);
+    }
+
+    /**
+     * Loads preferences configuration into the current object.
+     *
+     * @param string $app  The application.
+     */
+    protected function _loadPrefs($app, $merge = false)
+    {
+        try {
+            $res = Horde::loadConfiguration('prefs.php', array('prefGroups', '_prefs'), $app);
+            $this->prefGroups = $res['prefGroups'];
+            $this->prefs = $res['_prefs'];
+        } catch (Horde_Exception $e) {
+            $this->prefGroups = $this->prefs = array();
+        }
+
+        /* If there's only one prefGroup, just show it. */
+        if (!$this->group && (count($this->prefGroups) == 1)) {
+            reset($this->prefGroups);
+            $this->group = key($this->prefGroups);
+        }
+    }
+
+    /**
+     * Get the list of viewable preference groups, filtering out suppressed
+     * groups and groups with no settable prefs.
+     *
+     * @return array  The filtered prefGroups array.
+     */
+    protected function _getPrefGroups()
+    {
+        $out = array();
+
+        foreach (array_diff(array_keys($this->prefGroups), $this->suppressGroups) as $val) {
+            if ($this->groupIsEditable($val)) {
+                $out[$val] = $this->prefGroups[$val];
+            }
+        }
+
+        return $out;
+    }
+
+}
diff --git a/framework/Core/lib/Horde/Core/Prefs/Ui/Widgets.php b/framework/Core/lib/Horde/Core/Prefs/Ui/Widgets.php
new file mode 100644 (file)
index 0000000..b4a43ee
--- /dev/null
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Collection of prefs UI widgets for use with application-specific (a/k/a
+ * 'special') configuration.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author   Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package  Core
+ */
+class Horde_Core_Prefs_Ui_Widgets
+{
+    /* Source selection widget. */
+
+    /**
+     * Code to run on init.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    static public function sourceInit($ui)
+    {
+        Horde::addScriptFile('sourceselect.js', 'horde');
+    }
+
+    /**
+     * Create code needed for source selection.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param array $data              REQUIRED data items:
+     * <pre>
+     * 'mainlabel'
+     * 'selected'
+     * 'selectlabel'
+     * 'unselected'
+     * 'unselectlabel'
+     * </pre>
+     *
+     * @return string  HTML UI code.
+     */
+    static public function source($ui, $data = array())
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('mainlabel', $data['mainlabel']);
+        $t->set('selectlabel', $data['selectlabel']);
+        $t->set('unselectlabel', $data['unselectlabel']);
+
+        $unselected = array();
+        foreach ($data['unselected'] as $key => $val) {
+            $unselected[] = array(
+                'l' => $val,
+                'v' => $key
+            );
+        }
+        $t->set('unselected', $unselected);
+
+        $selected = array();
+        foreach ($data['selected'] as $key => $val) {
+            $selected[] = array(
+                'l' => $val,
+                'v' => $key
+            );
+        }
+        $t->set('selected', $selected);
+
+        $t->set('addimg', Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'lhand.png' : 'rhand.png', _("Add source")));
+        $t->set('removeimg', Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'rhand.png' : 'lhand.png', _("Remove source")));
+
+        $t->set('upimg', Horde::img('nav/up.png', _("Move up")));
+        $t->set('downimg', Horde::img('nav/down.png', _("Move down")));
+
+        return $t->fetch(HORDE_TEMPLATES . '/prefs/source.html');
+    }
+
+    /* Addressbook selection widget. Extends the source widget to handle
+     * the special case of addressbook selection. */
+
+    /**
+     * Code to run on init for addressbook selection.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    static public function addressbooksInit($ui)
+    {
+        self::sourceInit($ui);
+        Horde::addScriptFile('addressbooksprefs.js', 'horde');
+    }
+
+    /**
+     * Create code needed for addressbook selection.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    static public function addressbooks($ui)
+    {
+        global $prefs, $registry;
+
+        $selected = $unselected = array();
+        $out = '';
+
+        if (!$registry->hasMethod('contacts/sources') ||
+            $prefs->isLocked('search_sources')) {
+            return;
+        }
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        try {
+            $readable = $registry->call('contacts/sources');
+        } catch (Horde_Exception $e) {
+            $readable = array();
+        }
+
+        try {
+            $writeable = $registry->call('contacts/sources', array(true));
+        } catch (Horde_Exception $e) {
+            $writeable = array();
+        }
+
+        $search = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
+
+        if (count($readable) == 1) {
+            // Only one source, no need to display the selection widget
+            $search['sources'] = array_keys($readable);
+        }
+
+        foreach ($search['sources'] as $source) {
+            if (!empty($readable[$source])) {
+                $selected[$source] = $readable[$source];
+            }
+        }
+
+        foreach (array_diff(array_keys($readable), $search['sources']) as $val) {
+            $unselected[$val] = $readable[$val];
+        }
+
+        if (!empty($selected) || !empty($unselected)) {
+            $out = Horde_Core_Prefs_Ui_Widgets::source($ui, array(
+                  'mainlabel' => _("Choose the order of address books to search when expanding addresses."),
+                  'selected' => $selected,
+                  'selectlabel' => _("Selected address books:"),
+                  'unselected' => $unselected,
+                  'unselectlabel' => _("Available address books:")
+             ));
+
+            $t->set('selected', count($unselected) > 1);
+
+            $js = array();
+            foreach (array_keys($readable) as $source) {
+                $tmp = array($source);
+
+                try {
+                    foreach ($registry->call('contacts/fields', array($source)) as $field) {
+                        if ($field['search']) {
+                            $tmp[] = array($field['name'], $field['label'], isset($search['fields'][$source]) && in_array($field['name'], $search['fields'][$source]));
+                        }
+                    }
+                } catch (Horde_Exception $e) {}
+
+                $js[] = $tmp;
+            }
+
+            Horde::addInlineScript(array(
+                'HordeAddressbooksPrefs.fields = ' . Horde_Serialize::serialize($js, Horde_Serialize::JSON, Horde_Nls::getCharset())
+            ));
+        }
+
+        return $out . $t->fetch(HORDE_TEMPLATES . '/prefs/addressbooks.html');
+    }
+
+    /**
+     * Update prefs for addressbook selection.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return boolean  True if preferences were updated.
+     */
+    static public function addressbooksUpdate($ui)
+    {
+        $updated = false;
+
+        if (isset($ui->vars->sources)) {
+            $GLOBALS['prefs']->setValue('search_sources', implode("\t", Horde_Serialize::unserialize($ui->vars->sources, Horde_Serialize::JSON)));
+            $updated = true;
+        }
+
+        if (isset($ui->vars->search_fields_string)) {
+            $GLOBALS['prefs']->setValue('search_fields', $ui->vars->search_fields_string);
+            $updated = true;
+        }
+
+        return $updated;
+    }
+
+}
diff --git a/framework/Core/lib/Horde/Core/Prefs/Utils.php b/framework/Core/lib/Horde/Core/Prefs/Utils.php
new file mode 100644 (file)
index 0000000..cd26036
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Collection of prefs UI utilities for use with common preferences.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author   Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package  Core
+ */
+class Horde_Core_Prefs_Utils
+{
+    /**
+     * Determines parameters needed to do an address search
+     *
+     * @return array  An array with two keys: 'sources' and 'fields'.
+     */
+    static public function getAddressbookSearchParams()
+    {
+        $src = explode("\t", $GLOBALS['prefs']->getValue('search_sources'));
+        if ((count($src) == 1) && empty($src[0])) {
+            $src = array();
+        }
+
+        $fields = array();
+        if (($val = $GLOBALS['prefs']->getValue('search_fields'))) {
+            $field_arr = explode("\n", $val);
+            foreach ($field_arr as $field) {
+                $field = trim($field);
+                if (!empty($field)) {
+                    $tmp = explode("\t", $field);
+                    if (count($tmp) > 1) {
+                        $source = array_splice($tmp, 0, 1);
+                        $fields[$source[0]] = $tmp;
+                    }
+                }
+            }
+        }
+
+        return array(
+            'fields' => $fields,
+            'sources' => $src
+        );
+    }
+
+}
index b4fc4ce..f3eff0d 100644 (file)
@@ -95,4 +95,56 @@ class Horde_Registry_Application
     {
     }
 
+    // Horde_Core_Prefs_Ui functions.
+
+    /**
+     * Code to run if the language preference changes.
+     */
+    // public function changeLanguage() {}
+
+    /**
+     * Code to run on init when viewing prefs for this application.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    // public function prefsInit($ui) {}
+
+    /**
+     * Called when preferences are changed.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    // public function prefsCallback($ui) {}
+
+    /**
+     * Generate the menu to use on the prefs page.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return Horde_Menu  The Horde_Menu object to display.
+     */
+    // public function prefsMenu($ui) {}
+
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    // public function prefsSpecial($ui, $item) {}
+
+    /**
+     * Special preferences handling on update.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return boolean  True if preference was updated.
+     */
+    // public function prefsSpecialUpdate($ui, $item) {}
+
+    // END Horde_Core_Prefs_Ui functions.
+
 }
index 965847e..276a625 100644 (file)
@@ -41,9 +41,8 @@ class Horde_Script_Files
      */
     public function add($file, $app = null, $direct = false, $full = false)
     {
-        $res = $this->_add($file, $app, $direct, $full);
-
-        if (($res === false) || (!ob_get_length() && !headers_sent())) {
+        if (($this->_add($file, $app, $direct, $full) === false) ||
+            !(ob_get_length() && headers_sent())) {
             return;
         }
 
index 4dae572..2b5aa1c 100644 (file)
@@ -37,7 +37,8 @@ Application Framework.
   <api>beta</api>
  </stability>
  <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>* Convert from PEAR Log to Horde_Log for logging.
+ <notes>* Import prefs UI handling class from Horde_Prefs.
+ * Convert from PEAR Log to Horde_Log for logging.
  * Add Horde_Themes:: class.
  * Add Horde::nocacheUrl().
  * Remove dependency on Horde_DOM package.
@@ -93,6 +94,13 @@ Application Framework.
        <file name="Hordelog.php" role="php" />
        <file name="Status.php" role="php" />
       </dir> <!-- /lib/Horde/Core/Notification -->
+      <dir name="Prefs">
+       <dir name="Ui">
+        <file name="Widgets.php" role="php" />
+       </dir> <!-- /lib/Horde/Core/Prefs/Ui -->
+       <file name="Ui.php" role="php" />
+       <file name="Utils.php" role="php" />
+      </dir> <!-- /lib/Horde/Core/Prefs -->
      </dir> <!-- /lib/Horde/Core -->
      <file name="ErrorHandler.php" role="php" />
      <dir name="Exception">
@@ -226,6 +234,9 @@ Application Framework.
    <install name="lib/Horde/Core/Log/Logger.php" as="Horde/Core/Log/Logger.php" />
    <install name="lib/Horde/Core/Notification/Hordelog.php" as="Horde/Core/Notification/Hordelog.php" />
    <install name="lib/Horde/Core/Notification/Status.php" as="Horde/Core/Notification/Status.php" />
+   <install name="lib/Horde/Core/Prefs/Ui/Widgets.php" as="Horde/Core/Prefs/Ui/Widgets.php" />
+   <install name="lib/Horde/Core/Prefs/Ui.php" as="Horde/Core/Prefs/Ui.php" />
+   <install name="lib/Horde/Core/Prefs/Utils.php" as="Horde/Core/Prefs/Utils.php" />
    <install name="lib/Horde/ErrorHandler.php" as="Horde/ErrorHandler.php" />
    <install name="lib/Horde/Exception/HookNotSet.php" as="Horde/Exception/HookNotSet.php" />
    <install name="lib/Horde/Help.php" as="Horde/Help.php" />
index ea92366..929576b 100644 (file)
@@ -4,36 +4,14 @@
  * various preferences storage mediums.  It also includes all of the
  * functions for retrieving, storing, and checking preference values.
  *
- * TODO: document the format of the $_prefs hash here
- *
- * $_prefs[*pref name*] = array(
- *     'value'  => *Default value*,
- *     'locked' => *boolean*,
- *     'shared' => *boolean*,
- *     'type'   => 'checkbox'
- *                 'text'
- *                 'password'
- *                 'textarea'
- *                 'select'
- *                 'number'
- *                 'implicit'
- *                 'special'
- *                 'link' - There must be a field named either 'url'
- *                          (internal application link) or 'xurl'
- *                          (external application link) if this type is used.
- *                 'enum'
- *     'enum'   => TODO,
- *     'desc'   => _(*Description string*),
- *     'help'   => *Name of the entry in the XML help file*
- * );
- *
  * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (LGPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  *
- * @author  Jon Parise <jon@horde.org>
- * @package Horde_Prefs
+ * @author   Jon Parise <jon@horde.org>
+ * @category Horde
+ * @package  Prefs
  */
 class Horde_Prefs
 {
@@ -62,9 +40,9 @@ class Horde_Prefs
      * itself a hash, so this will ultimately be multi-dimensional.
      *
      * [*pref name*] => Array(
-     *     [d]  =>  *default value*
-     *     [m]  =>  *pref mask*
-     *     [v]  =>  *pref value*
+     *     [d] => (string) Default value
+     *     [m] => (integer) Pref mask
+     *     [v] => (string) Current pref value
      * )
      *
      * @var array
@@ -332,6 +310,9 @@ class Horde_Prefs
         return $result;
     }
 
+    /**
+     * Shortcut to setValue().
+     */
     public function __set($name, $value)
     {
         return $this->setValue($name, $value);
@@ -375,7 +356,7 @@ class Horde_Prefs
         if (isset($GLOBALS['conf']['prefs']['maxsize']) &&
             (strlen($val) > $GLOBALS['conf']['prefs']['maxsize']) &&
             isset($GLOBALS['notification'])) {
-            $GLOBALS['notification']->push(sprintf(_("The preference \"%s\" could not be saved because its data exceeded the maximum allowable size"), $pref), 'horde.error');
+            $GLOBALS['notification']->push(sprintf(_("The preference \"%s\" could not be saved because its data exceeds the maximum allowable size"), $pref), 'horde.error');
             return false;
         }
 
@@ -425,6 +406,9 @@ class Horde_Prefs
         return $value;
     }
 
+    /**
+     * Shortcut to getValue().
+     */
     public function __get($name)
     {
         return $this->getValue($name);
@@ -781,56 +765,50 @@ class Horde_Prefs
          * the default values. */
         try {
             $result = Horde::loadConfiguration('prefs.php', array('_prefs'), $scope);
-            if (empty($result)) {
+            if (empty($result) || !isset($result['_prefs'])) {
                 return;
             }
         } catch (Horde_Exception $e) {
             return;
         }
 
-        extract($result);
-        if (!isset($_prefs)) {
-            return;
-        }
+        foreach ($result['_prefs'] as $name => $pref) {
+            if (!isset($pref['value'])) {
+                continue;
+            }
 
-        foreach ($_prefs as $name => $pref) {
-            if (isset($pref['value']) &&
-                isset($pref['locked']) &&
-                isset($pref['shared']) &&
-                ($pref['type'] != 'link') &&
-                ($pref['type'] != 'special')) {
-                $name = str_replace('.', '_', $name);
+            $name = str_replace('.', '_', $name);
 
-                $mask = 0;
-                $mask &= ~self::DIRTY;
-                $mask |= self::PREFS_DEFAULT;
+            $mask = 0;
+            $mask &= ~self::DIRTY;
+            $mask |= self::PREFS_DEFAULT;
 
-                if ($pref['locked']) {
-                    $mask |= self::LOCKED;
-                }
+            if (!empty($pref['locked'])) {
+                $mask |= self::LOCKED;
+            }
 
-                if ($pref['shared'] || ($scope == 'horde')) {
-                    $mask |= self::SHARED;
-                    $pref_scope = 'horde';
-                } else {
-                    $pref_scope = $scope;
-                }
+            if (empty($pref['shared'])) {
+                $pref_scope = $scope;
+            } else {
+                $mask |= self::SHARED;
+                $pref_scope = 'horde';
+            }
 
-                if ($pref['shared'] && isset($this->_scopes[$pref_scope][$name])) {
-                    // This is a shared preference that was already
-                    // retrieved.
-                    $this->_scopes[$pref_scope][$name]['m'] = $mask & ~self::PREFS_DEFAULT;
-                    $this->_scopes[$pref_scope][$name]['d'] = $pref['value'];
-                } else {
-                    $this->_scopes[$pref_scope][$name] = array('v' => $pref['value'], 'm' => $mask, 'd' => $pref['value']);
-                }
+            if (!empty($pref['shared']) &&
+                isset($this->_scopes[$pref_scope][$name])) {
+                // This is a shared preference that was already retrieved.
+                $this->_scopes[$pref_scope][$name]['m'] = $mask & ~self::PREFS_DEFAULT;
+                $this->_scopes[$pref_scope][$name]['d'] = $pref['value'];
+            } else {
+                $this->_scopes[$pref_scope][$name] = array(
+                    'd' => $pref['value'],
+                    'm' => $mask,
+                    'v' => $pref['value']
+                );
+            }
 
-                if (!empty($pref['hook'])) {
-                    if (!isset($this->_hooks[$scope])) {
-                        $this->_hooks[$scope] = array();
-                    }
-                    $this->_hooks[$scope][$name] = $pref_scope;
-                }
+            if (!empty($pref['hook'])) {
+                $this->_hooks[$scope][$name] = $pref_scope;
             }
         }
     }
index f339ec0..a6a7b60 100644 (file)
@@ -10,7 +10,7 @@
  *
  * @author   Chuck Hagenbuch <chuck@horde.org>
  * @category Horde
- * @package  Horde_Prefs
+ * @package  Prefs
  */
 class Horde_Prefs_CategoryManager
 {
diff --git a/framework/Prefs/lib/Horde/Prefs/Credentials.php b/framework/Prefs/lib/Horde/Prefs/Credentials.php
deleted file mode 100644 (file)
index a2d7fb3..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-/**
- * Class for handling a list of credentials stored in a user's preferences.
- *
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author   Jan Schneider <jan@horde.org>
- * @category Horde
- * @package  Horde_Prefs
- */
-class Horde_Prefs_Credentials
-{
-    /**
-     * Singleton instance.
-     *
-     * @var Horde_Prefs_Credentials
-     */
-    static protected $_instance = null;
-
-    /**
-     * Cache for getCredentials().
-     *
-     * @var array
-     */
-    static protected $_credentialsCache = null;
-
-    /**
-     * The Horde application currently processed.
-     *
-     * @see singleton()
-     * @var string
-     */
-    protected $app;
-
-    /**
-     * A list of preference field names and their values.
-     *
-     * @var array
-     */
-    protected $_credentials = array();
-
-    /**
-     * Constructor.
-     */
-    public function __construct()
-    {
-        $credentials = @unserialize($GLOBALS['prefs']->getValue('credentials'));
-        if ($credentials) {
-            foreach ($credentials as $app => $app_prefs) {
-                foreach ($app_prefs as $name => $value) {
-                    $this->_credentials['credentials[' . $app . '][' . $name . ']'] = $value;
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns a single instance of the Prefs_Credentials class, and sets the
-     * curently processed application.
-     *
-     * @param string $app  The current application.
-     *
-     * @return Prefs_Credentials  A Prefs_Credentials instance.
-     */
-    static public function singleton($app)
-    {
-        if (is_null(self::$_instance)) {
-            self::$_instance = new self();
-        }
-        self::$_instance->app = $app;
-
-        return self::$_instance;
-    }
-
-    /**
-     * Returns a list of available credentials collected from all Horde
-     * applications.
-     *
-     * @return array  A list of Horde applications and their credentials.
-     */
-    static public function getCredentials()
-    {
-        if (!is_null(self::$_credentialsCache)) {
-            return self::$_credentialsCache;
-        }
-
-        self::$_credentialsCache = array();
-        foreach ($GLOBALS['registry']->listApps() as $app) {
-            try {
-                $credentials = $GLOBALS['registry']->callAppMethod($app, 'authCredentials');
-            } catch (Horde_Exception $e) {
-                continue;
-            }
-
-            if (!count($credentials)) {
-                continue;
-            }
-
-            self::$_credentialsCache[$app] = array();
-            foreach ($credentials as $name => $credential) {
-                $pref = 'credentials[' . $app . '][' . $name . ']';
-                $credential['shared'] = true;
-                self::$_credentialsCache[$app][$pref] = $credential;
-            }
-        }
-
-        return self::$_credentialsCache;
-    }
-
-    /**
-     * Displays the preference interface for setting all available
-     * credentials.
-     */
-    static public function showUi()
-    {
-        $credentials = self::getCredentials();
-        $vspace = '';
-        foreach ($credentials as $app => $_prefs) {
-            $prefs = Horde_Prefs_Credentials::singleton($app);
-            echo $vspace . '<h2 class="smallheader">';
-            printf(_("%s authentication credentials"),
-                   $GLOBALS['registry']->get('name', $app));
-            echo '</h2>';
-            foreach (array_keys($_prefs) as $pref) {
-                $helplink = empty($_prefs[$pref]['help'])
-                    ? null
-                    : Horde_Help::link(!empty($_prefs[$pref]['shared']) ? 'horde' : $GLOBALS['registry']->getApp(), $_prefs[$pref]['help']);
-                require $GLOBALS['registry']->get('templates') . '/prefs/' . $_prefs[$pref]['type'] . '.inc';
-            }
-            $vspace = '<br />';
-        }
-    }
-
-    /**
-     * Returns the value of a credential for the currently processed
-     * application.
-     *
-     * @see Horde_Prefs::getValue()
-     *
-     * @param string $pref  A credential name.
-     *
-     * @return mixed  The credential's value, either from the user's
-     *                preferences, or from the default value, or null.
-     */
-    public function getValue($pref)
-    {
-        if (isset($this->_credentials[$pref])) {
-            return $this->_credentials[$pref];
-        }
-        $credentials = $this->getCredentials();
-
-        return isset($credentials[$this->app][$pref]['value'])
-            ? $credentials[$this->app][$pref]['value']
-            : null;
-    }
-
-}
index 34b4279..064a8bf 100644 (file)
@@ -9,7 +9,7 @@
  *
  * @author   Thomas Jarosch <thomas.jarosch@intra2net.com>
  * @category Horde
- * @package  Horde_Prefs
+ * @package  Prefs
  */
 class Horde_Prefs_File extends Horde_Prefs
 {
index 7982105..b40795d 100644 (file)
@@ -11,8 +11,9 @@
  * See the enclosed file COPYING for license information (LGPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  *
- * @author  Jan Schneider <jan@horde.org>
- * @package Horde_Prefs
+ * @author   Jan Schneider <jan@horde.org>
+ * @category Horde
+ * @package  Prefs
  */
 class Horde_Prefs_Identity
 {
index 095e4ab..c647f69 100644 (file)
@@ -7,8 +7,9 @@
  * See the enclosed file COPYING for license information (LGPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  *
- * @author  Michael Rubinsky <mrubinsk@horde.org>
- * @package Horde_Prefs
+ * @author   Michael Rubinsky <mrubinsk@horde.org>
+ * @category Horde
+ * @package  Prefs
  */
 class Horde_Prefs_Imsp extends Horde_Prefs
 {
index 41796aa..0159e63 100644 (file)
@@ -11,7 +11,7 @@
  *
  * @author   Stuart Binge <s.binge@codefusion.co.za>
  * @category Horde
- * @package  Horde_Prefs
+ * @package  Prefs
  */
 class Horde_Prefs_Kolab extends Horde_Prefs_Ldap
 {
index 063550f..63b8343 100644 (file)
@@ -7,8 +7,9 @@
  * See the enclosed file COPYING for license information (LGPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  *
- * @author  Gunnar Wrobel <p@rdus.de>
- * @package Horde_Prefs
+ * @author   Gunnar Wrobel <p@rdus.de>
+ * @category Horde
+ * @package  Prefs
  */
 class Horde_Prefs_KolabImap extends Horde_Prefs
 {
index bf90c97..d2e1658 100644 (file)
@@ -49,7 +49,7 @@
  * @author   Jon Parise <jon@horde.org>
  * @author   Ben Klang <ben@alkaloid.net>
  * @category Horde
- * @package  Horde_Prefs
+ * @package  Prefs
  */
 class Horde_Prefs_Ldap extends Horde_Prefs
 {
index 8a3bc22..9bc62be 100644 (file)
@@ -7,8 +7,9 @@
  * See the enclosed file COPYING for license information (LGPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  *
- * @author  Jon Parise <jon@horde.org>
- * @package Horde_Prefs
+ * @author   Jon Parise <jon@horde.org>
+ * @category Horde
+ * @package  Prefs
  */
 class Horde_Prefs_Session extends Horde_Prefs
 {
index fd3a250..967a742 100644 (file)
@@ -46,7 +46,7 @@
  *
  * @author   Jon Parise <jon@horde.org>
  * @category Horde
- * @package  Horde_Prefs
+ * @package  Prefs
  */
 class Horde_Prefs_Sql extends Horde_Prefs
 {
diff --git a/framework/Prefs/lib/Horde/Prefs/Ui.php b/framework/Prefs/lib/Horde/Prefs/Ui.php
deleted file mode 100644 (file)
index 2531da0..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-<?php
-/**
- * Class for auto-generating the preferences user interface and processing
- * the forms.
- *
- * Set $_SESSION['horde_prefs']['nomenu'] to true to suppress output of the
- * Horde_Menu on the options pages.
- *
- * For 'special' group types, set 'prefsui_no_save' to suppress printing of
- * the "Save Changes" and "Undo Changes" buttons.
- *
- * The following Application API callbacks are available:
- * prefsCallback($group) - TODO
- * prefsInit($group = '') - TODO
- * prefsMenu() - TODO
- * prefsSpecial($pref, $updated) - TODO
- * prefsSpecialGenerate($pref) - TODO
- *
- * Copyright 2001-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @category Horde
- * @package  Horde_Prefs
- */
-class Horde_Prefs_Ui
-{
-    /**
-     * Cache for groupIsEditable().
-     *
-     * @var array
-     */
-    static protected $_results = array();
-
-    /**
-     * Determine whether or not a preferences group is editable.
-     *
-     * @param string $group      The preferences group to check.
-     * @param array $prefGroups  TODO
-     *
-     * @return boolean  Whether or not the group is editable.
-     */
-    static public function groupIsEditable($group, $prefGroups)
-    {
-        if (!isset(self::$_results[$group])) {
-            if (!empty($prefGroups[$group]['url'])) {
-                self::$_results[$group] = true;
-            } else {
-                self::$_results[$group] = false;
-                if (isset($prefGroups[$group]['members'])) {
-                    foreach ($prefGroups[$group]['members'] as $pref) {
-                        if (!$GLOBALS['prefs']->isLocked($pref)) {
-                            self::$_results[$group] = true;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        return self::$_results[$group];
-    }
-
-    /**
-     * Handle a preferences form submission if there is one, updating
-     * any preferences which have been changed.
-     *
-     * @param string $group      The preferences group that was edited.
-     * @param object $save       The object where the changed values are
-     *                           saved. Must implement setValue(string,
-     *                           string).
-     * @param string $app        The application name.
-     * @param array $prefGroups  TODO
-     * @param array $_prefs      TODO
-     *
-     * @return boolean  Whether preferences have been updated.
-     */
-    static public function handleForm($group, $save, $app, $prefGroups, $_prefs)
-    {
-        global $notification, $prefs, $registry;
-
-        $updated = false;
-
-        /* Run through the action handlers */
-        if (self::groupIsEditable($group, $prefGroups)) {
-            foreach ($prefGroups[$group]['members'] as $pref) {
-                if (!$prefs->isLocked($pref) ||
-                    ($_prefs[$pref]['type'] == 'special')) {
-                    switch ($_prefs[$pref]['type']) {
-                    case 'implicit':
-                    case 'link':
-                        /* These either aren't set or are set in other
-                         * parts of the UI. */
-                        break;
-
-                    case 'password':
-                    case 'select':
-                    case 'text':
-                    case 'textarea':
-                        $updated = $updated | $save->setValue($pref, Horde_Util::getPost($pref));
-                        break;
-
-                    case 'enum':
-                        $val = Horde_Util::getPost($pref);
-                        if (isset($_prefs[$pref]['enum'][$val])) {
-                            $updated = $updated | $save->setValue($pref, $val);
-                        } else {
-                            $notification->push(_("An illegal value was specified."), 'horde.error');
-                        }
-                        break;
-
-                    case 'multienum':
-                        $vals = Horde_Util::getPost($pref);
-                        $set = array();
-                        if (is_array($vals)) {
-                            foreach ($vals as $val) {
-                                if (isset($_prefs[$pref]['enum'][$val])) {
-                                    $set[] = $val;
-                                } else {
-                                    $notification->push(_("An illegal value was specified."), 'horde.error');
-                                    break 2;
-                                }
-                            }
-                        }
-
-                        $updated = $updated | $save->setValue($pref, @serialize($set));
-                        break;
-
-                    case 'number':
-                        $num = Horde_Util::getPost($pref);
-                        if ((string)(double)$num !== $num) {
-                            $notification->push(_("This value must be a number."), 'horde.error');
-                        } elseif (empty($num)) {
-                            $notification->push(_("This number must be at least one."), 'horde.error');
-                        } else {
-                            $updated = $updated | $save->setValue($pref, $num);
-                        }
-                        break;
-
-                    case 'checkbox':
-                        $val = Horde_Util::getPost($pref);
-                        $updated = $updated | $save->setValue($pref, isset($val) ? 1 : 0);
-                        break;
-
-                    case 'alarm':
-                        $methods = Horde_Alarm::notificationMethods();
-                        $value = array();
-                        foreach (Horde_Util::getPost($pref, array()) as $method) {
-                            $value[$method] = array();
-                            if (!empty($methods[$method])) {
-                                foreach (array_keys($methods[$method]) as $param) {
-                                    $value[$method][$param] = Horde_Util::getPost($pref . '_' . $param, '');
-                                    if (is_array($methods[$method][$param]) &&
-                                        $methods[$method][$param]['required'] &&
-                                        $value[$method][$param] === '') {
-                                        $notification->push(sprintf(_("You must provide a setting for \"%s\"."), $methods[$method][$param]['desc']), 'horde.error');
-                                        $updated = false;
-                                        break 3;
-                                    }
-                                }
-                            }
-                        }
-                        $updated = $updated | $save->setValue($pref, serialize($value));
-                        break;
-
-                    case 'special':
-                        /* Code for special elements written specifically for
-                         * each application. */
-                        if ($registry->hasAppMethod($app, 'prefsSpecial')) {
-                            $updated = $updated | $registry->callAppMethod($app, 'prefsSpecial', array('args' => array($pref, $updated)));
-                        }
-                        break;
-                    }
-                }
-            }
-
-            if (is_callable(array($save, 'verify'))) {
-                $result = $save->verify();
-                if ($result instanceof PEAR_Error) {
-                    $notification->push($result, 'horde.error');
-                    $updated = false;
-                }
-            }
-        }
-
-        if ($updated) {
-            if ($registry->hasAppMethod($app, 'prefsCallback')) {
-                $registry->callAppMethod($app, 'prefsCallback', array('args' => array($group)));
-            }
-
-            if ($prefs instanceof Horde_Prefs_Session) {
-                $notification->push(_("Your options have been updated for the duration of this session."), 'horde.success');
-            } else {
-                $notification->push(_("Your options have been updated."), 'horde.success');
-            }
-        }
-
-        return $updated;
-    }
-
-    /**
-     * Generate the UI for the preferences interface, either for a
-     * specific group, or the group selection interface.
-     *
-     * @param string $app        The application name.
-     * @param array $prefGroups  TODO
-     * @param array $_prefs      TODO
-     * @param string $group      The group to generate the UI for.
-     * @param boolean $chunk     Whether to only return the body part.
-     */
-    static public function generateUI($app, $prefGroups, $_prefs,
-                                      $group = null, $chunk = false)
-    {
-        global $browser, $conf, $notification, $prefs, $registry;
-
-        /* Check if any options are actually available. */
-        if (is_null($prefGroups)) {
-            $notification->push(_("There are no options available."), 'horde.message');
-        }
-
-        /* Assign variables to hold select lists. */
-        if (!$prefs->isLocked('language')) {
-            $GLOBALS['language_options'] = Horde_Nls::$config['languages'];
-            array_unshift($GLOBALS['language_options'], _("Default"));
-        }
-
-        $columns = array();
-        $in_group = (!empty($group) && self::groupIsEditable($group, $prefGroups) && !empty($prefGroups[$group]['members']));
-
-        /* We need to do this check up here because it is possible that
-         * we will generate a notification object, which is handled by
-         * generateHeader. */
-        if (!$in_group && is_array($prefGroups)) {
-            foreach ($prefGroups as $key => $val) {
-                if (self::groupIsEditable($key, $prefGroups)) {
-                    $col = $val['column'];
-                    unset($val['column']);
-                    $columns[$col][$key] = $val;
-                }
-            }
-            if (!count($columns)) {
-                $notification->push(_("There are no options available."), 'horde.message');
-            }
-        }
-
-        self::generateHeader($app, $prefGroups, $group, $chunk);
-
-        if ($in_group) {
-            foreach ($prefGroups[$group]['members'] as $pref) {
-                if (!$prefs->isLocked($pref)) {
-                    /* Get the help link. */
-                    $helplink = empty($_prefs[$pref]['help'])
-                        ? null
-                        : Horde_Help::link(!empty($_prefs[$pref]['shared']) ? 'horde' : $registry->getApp(), $_prefs[$pref]['help']);
-
-                    switch ($_prefs[$pref]['type']) {
-                    case 'implicit':
-                        break;
-
-                    case 'special':
-                        if (!$registry->hasAppMethod($app, 'prefsSpecialGenerate') ||
-                            $registry->callAppMethod($app, 'prefsSpecialGenerate', array('args' => array($pref)))) {
-                            require $registry->get('templates', empty($_prefs[$pref]['shared']) ? $registry->getApp() : 'horde') . '/prefs/' . $pref . '.inc';
-                        }
-                        break;
-
-                    default:
-                        require $registry->get('templates', 'horde') . '/prefs/' . $_prefs[$pref]['type'] . '.inc';
-                        break;
-                    }
-                }
-            }
-            require $registry->get('templates', 'horde') . '/prefs/end.inc';
-        } elseif (count($columns)) {
-            $span = round(100 / count($columns));
-            require $registry->get('templates', 'horde') . '/prefs/overview.inc';
-        }
-    }
-
-    /**
-     * Generates the the full header of a preference screen including
-     * menu and navigation bars.
-     *
-     * @param string $app        The application name.
-     * @param array $prefGroups  TODO
-     * @param string $group      The group to generate the header for.
-     * @param boolean $chunk     Whether to only return the body part.
-     */
-    static public function generateHeader($app, $prefGroups = null,
-                                          $group = null, $chunk = false)
-    {
-        global $notification, $prefs, $registry;
-
-        $title = _("User Options");
-        if ($group == 'identities' && !$prefs->isLocked('default_identity')) {
-            Horde::addInlineScript(array('IdentitySelect.newChoice()'), 'dom');
-        }
-        $GLOBALS['bodyId'] = 'services_prefs';
-        if (!$chunk) {
-            require $registry->get('templates', 'horde') . '/common-header.inc';
-
-            if (empty($_SESSION['horde_prefs']['nomenu'])) {
-                if ($registry->hasAppMethod($app, 'prefsMenu')) {
-                    $menu = $registry->callAppMethod($app, 'prefsMenu');
-                }
-                require $registry->get('templates', 'horde') . '/menu/menu.inc';
-            }
-
-            $notification->notify(array('listeners' => 'status'));
-        }
-
-        /* Get list of accessible applications. */
-        $apps = array();
-        foreach ($registry->applications as $application => $params) {
-            // Make sure the app is installed and has a prefs file.
-            if (!file_exists($registry->get('fileroot', $application) . '/config/prefs.php')) {
-                continue;
-            }
-
-            if ($params['status'] == 'heading' ||
-                $params['status'] == 'block') {
-                continue;
-            }
-
-            /* Check if the current user has permisson to see this
-             * application, and if the application is active.
-             * Administrators always see all applications. */
-            if ((Horde_Auth::isAdmin() && $params['status'] != 'inactive') ||
-                ($registry->hasPermission($application) &&
-                 ($params['status'] == 'active' || $params['status'] == 'notoolbar'))) {
-                $apps[$application] = _($params['name']);
-            }
-        }
-        asort($apps);
-
-        /* Show the current application and a form for switching
-         * applications. */
-        require $registry->get('templates', 'horde') . '/prefs/app.inc';
-
-        if (is_null($prefGroups)) {
-            extract(Horde::loadConfiguration('prefs.php', array('prefGroups'), $app));
-        }
-
-        /* If there's only one prefGroup, just show it. */
-        if (empty($group) && count($prefGroups) == 1) {
-            $group = array_keys($prefGroups);
-            $group = array_pop($group);
-        }
-
-        if (!empty($group) && self::groupIsEditable($group, $prefGroups)) {
-            require $registry->get('templates', 'horde') . '/prefs/begin.inc';
-        }
-    }
-
-    /**
-     * Generate the content of the title bar navigation cell (previous | next
-     * option group).
-     *
-     * @param string $group  Current option group.
-     */
-    static public function generateNavigationCell($app, $group)
-    {
-        // Search for previous and next groups.
-        $first = $last = $next = $previous = null;
-        $finish = $found = false;
-
-        extract(Horde::loadConfiguration('prefs.php', array('prefGroups'), $app));
-
-        foreach ($prefGroups as $pgroup => $gval) {
-            if (self::groupIsEditable($pgroup, $prefGroups)) {
-                if (!$first) {
-                    $first = $pgroup;
-                }
-                if (!$found) {
-                    if ($pgroup == $group) {
-                        $previous = $last;
-                        $found = true;
-                    }
-                } elseif (!$finish) {
-                    $finish = true;
-                    $next = $pgroup;
-                }
-                $last = $pgroup;
-            }
-        }
-
-        if (!$previous) {
-            $previous = $last;
-        }
-
-        if (!$next) {
-            $next = $first;
-        }
-
-        /* Don't loop if there's only one group. */
-        if ($next == $previous) {
-            return;
-        }
-
-        echo '<ul><li>' .
-             Horde::link(Horde_Util::addParameter(Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/prefs.php'), array('app' => $app, 'group' => $previous), _("Previous options"))) .
-             '&lt;&lt; ' . $prefGroups[$previous]['label'] .
-             '</a>&nbsp;|&nbsp;' .
-             Horde::link(Horde_Util::addParameter(Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/prefs.php'), array('app' => $app, 'group' => $next), _("Next options"))) .
-             $prefGroups[$next]['label'] . ' &gt;&gt;' .
-             '</a></li></ul>';
-    }
-
-    /**
-     * Get the default application to show preferences for. Defaults
-     * to 'horde'.
-     */
-    static public function getDefaultApp()
-    {
-        $applications = $GLOBALS['registry']->listApps(null, true, Horde_Perms::READ);
-        return isset($applications['horde'])
-            ? 'horde'
-            : array_shift($applications);
-    }
-
-}
index e6665cb..c9485e7 100644 (file)
@@ -24,7 +24,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
   <api>beta</api>
  </stability>
  <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>* Initial Horde 4 package.
+ <notes>* Moved UI code to Horde_Core::.
+ * Initial Horde 4 package.
  </notes>
  <contents>
   <dir name="/">
@@ -32,7 +33,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
     <dir name="Horde">
      <dir name="Prefs">
       <file name="CategoryManager.php" role="php" />
-      <file name="Credentials.php" role="php" />
       <file name="File.php" role="php" />
       <file name="Identity.php" role="php" />
       <file name="Imsp.php" role="php" />
@@ -41,7 +41,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
       <file name="Ldap.php" role="php" />
       <file name="Session.php" role="php" />
       <file name="Sql.php" role="php" />
-      <file name="Ui.php" role="php" />
      </dir> <!-- /lib/Horde/Prefs -->
      <file name="Prefs.php" role="php" />
     </dir> <!-- /lib/Horde -->
@@ -85,7 +84,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
  <phprelease>
   <filelist>
    <install name="lib/Horde/Prefs/CategoryManager.php" as="Horde/Prefs/CategoryManager.php" />
-   <install name="lib/Horde/Prefs/Credentials.php" as="Horde/Prefs/Credentials.php" />
    <install name="lib/Horde/Prefs/File.php" as="Horde/Prefs/File.php" />
    <install name="lib/Horde/Prefs/Identity.php" as="Horde/Prefs/Identity.php" />
    <install name="lib/Horde/Prefs/Imsp.php" as="Horde/Prefs/Imsp.php" />
@@ -94,7 +92,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
    <install name="lib/Horde/Prefs/Ldap.php" as="Horde/Prefs/Ldap.php" />
    <install name="lib/Horde/Prefs/Session.php" as="Horde/Prefs/Session.php" />
    <install name="lib/Horde/Prefs/Sql.php" as="Horde/Prefs/Sql.php" />
-   <install name="lib/Horde/Prefs/Ui.php" as="Horde/Prefs/Ui.php" />
    <install name="lib/Horde/Prefs.php" as="Horde/Prefs.php" />
   </filelist>
  </phprelease>
@@ -111,8 +108,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
     <api>alpha</api>
    </stability>
    <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
-   <notes>* Add 'nomenu' option to hide menu generation in Prefs_UI::.
-   * Data in postgres must be stored in a BYTEA field, not a TEXT field (Bug #8130).
+   <notes>* Data in postgres must be stored in a BYTEA field, not a TEXT field (Bug #8130).
    * Converted to package.xml 2.0 for pear.horde.org
    * Added files-based preferences backend (thomas.jarosch@intra2net.com, Request #6653)
    </notes>
index f9d03d1..b58f0b3 100644 (file)
@@ -98,24 +98,21 @@ class Gollem_Application extends Horde_Registry_Application
     /**
      * Special preferences handling on update.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
      * @return boolean  True if preference was updated.
      */
-    public function prefsSpecial($item, $updated)
+    public function prefsSpecialUpdate($ui, $item)
     {
         switch ($item) {
         case 'columnselect':
-            $columns = Horde_Util::getFormData('columns');
-            if (!empty($columns)) {
-                $GLOBALS['prefs']->setValue('columns', $columns);
+            if (isset($ui->vars->columns)) {
+                $GLOBALS['prefs']->setValue('columns', $ui->vars->columns);
                 return true;
             }
             break;
         }
-
-        return $updated;
     }
 
     /**
index 952feab..ac3f0d2 100644 (file)
@@ -30,7 +30,9 @@
  *
  * Setting value
  * -------------
- * If 'hook' => true in a preference attribute, a hook named
+ * If
+ *   'hook' => true
+ * exists for a preference (config/prefs.php), a hook named
  * prefs_hook_<prefname> will be run on login. It receives the username as
  * the only parameter and the return value from the function will be used as
  * the preference value.
@@ -188,7 +190,7 @@ class Horde_Hooks
 //    // Example preferences change hook.
 //    function prefs_change_hook_theme()
 //    {
-//        $GLOBALS['notification']->push('You changed your theme to ' . $GLOBALS['prefs']->getValue('theme') . '!');
+//        $GLOBALS['notification']->push('You changed your theme to ' . $GLOBALS['prefs']->getValue('theme') . '.');
 //    }
 
 
index a1ce5d4..ace8408 100644 (file)
  * user logs out and logs in again.
  *
  * If you change these preferences in a production system, you will
- * need to delete any horde_prefs in your preferences database.
- *
- * prefGroups array
- * ----------------
- * $prefGroups are for display purposes when you press the options button.
- * The options choice will appear when you set your preferences driver
- * in the horde/config/conf.php file.
- *
- * $prefGroups array definition:
- *    column:  What column head this group will go under
- *     label:  Label for the group of settings
- *      desc:  Description that will show under label
- *   members:  List of preferences supported by this group
- *
- * _prefs array
- * ------------
- * The $_prefs array's are listed in the same order as listed in the
- * members element of $prefGroups.
- *
- *   value: This entry will hold the default preference value depending on the
- *          preference type:
- *            checkbox:  0 or false for unchecked, 1 or true for checked
- *                enum:  Preselected item from associated enumeration
- *            implicit:  See Preference type
- *                link:  Not used
- *              number:  Number value
- *            password:  Should be ''
- *              select:  Preselected item from associated selection list
- *             special:  Not used
- *                text:  Text value
- *            textarea:  Text value, lines separated with "\n"
- *
- *  locked: Allow preference to be changed from UI
- *             true:  Do not show this preference in the UI.
- *                    This has no effect on 'link' type preferences.
- *            false:  Show this preference in the UI and allow changing.
- *
- *  shared: Share with other horde apps
- *             true:  Share this pref with other Horde apps
- *            false:  Keep this pref local to the current app
- *
- *    type: Preference type
- *            checkbox:  Provides a checkbox.
- *                enum:  Provides a selection list in the UI, list is
- *                       specified in the associated 'enum' setting.
- *            implicit:  Provides storage for 'special' types.
- *                link:  Provides a link to another data entry form.
- *              number:  Provides a 3-character textbox to enter a natural
- *                       number; syntaxcheck is performed after data entry.
- *            password:  Provides a textbox for password entry.
- *              select:  Provides a selection list in the UI that is built in
- *                       lib/Application.php
- *             special:  Provides an UI widget.
- *                text:  Provides a single-line textbox.
- *            textarea:  Provides a multi-line textbox.
- *
- *    enum: Static list of elements for 'type' => 'enum'.
- *
- * escaped: For an enum or a select, are the keys and values already
- *          html-escaped? Defaults to false if not present.
- *
- *    hook: Call a hook function for the value of this preference
- *             true:  Will call the function prefs_hook_<prefname>
- *                    to fill in the value of this preference.
- *                    See hooks.php for more details.
- *            false:  Normal behaviour - no hook is called.
+ * need to delete these preference entries in your backend; entries in the
+ * backend have priority over the default entry.
+ *
+ * $prefGroups
+ * ===========
+ * $prefGroups defines the options page in which a preference value will
+ * appear in.
+ *
+ * Format:
+ * -------
+ * column - (string) Which column head this group will go under.
+ * desc - (string) Description shown under label.
+ * label - (string) Label for the group of settings.
+ * members - (array) List of displayable preferences contained in this group.
+ *
+ * $_prefs
+ * =======
+ * $_prefs defines the preferences used within an application.  Each
+ * preference is contained within a separate array entry, with the key being
+ * the name of the preference.
+ *
+ * The following are OPTIONAL values for each entry:
+ *
+ * locked - (boolean) Allow preference to be changed from the options screen?
+ *          VALUES:
+ *            true: Do not show this preference in the UI and don't allow
+ *                  changing by any mechanism.
+ *            false: Show this preference in the UI and allow changing.
+ *          DEFAULT: false
+ *
+ * shared - (boolean) Share with other Horde apps?
+ *          VALUES:
+ *            true: Share this pref with other Horde apps.
+ *            false: Keep this pref local to the current app.
+ *          DEFAULT: false
+ *
+ * help - (string) The help file identifier for this preference.
+ *        VALUES:
+ *          If present, a help icon will be displayed next to the preference.
+ *          Clicking on this icon will open the entry in the help viewer in
+ *          a popup window.
+ *        DEFAULT: No help icon is displayed
+ *
+ * The UI display for a preference is controlled by the 'type' key. This key
+ * controls how the preference is displayed on the options screen. If this
+ * key is not present, the preference is treated as type 'implict'. The
+ * following is the list of types, with a description of further keys used
+ * for each type.
+ *
+ * 'alarm'
+ * -------
+ * TODO
+ *
+ * 'checkbox'
+ * ----------
+ * Provides a checkbox (yes/no) entry.
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The description text to use on the options page.
+ *   'value' - (integer) 0 (or false) for unchecked, 1 (or true) for checked.
+ *             DEFAULT: 0
+ *
+ * 'enum'
+ * ------
+ * Provides an enumeration (a/k/a selection) list in the UI.
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The description text to use on the options page.
+ *   'escaped' - (boolean) If true, values in 'enum' are already escaped.
+ *               DEFAULT: false
+ *   'enum' - (array) The enumeration list. Keys will be used as the
+ *            prefernce value; values are the text that will be displayed in
+ *            the selection list.
+ *   'value' - (mixed) The value of the preference. Will be used to
+ *             auto-select the entry in the selection list.
+ *
+ * 'implicit'
+ * ----------
+ * Preference used in an application but never directly shown to the viewer
+ * via the preferences screen.
+ *
+ * ADDITIONAL KEYS:
+ *   'value' - (mixed) The value of the preference. Will be used to
+ *             auto-select the entry in the selection list.
+ *
+ * 'link'
+ * ------
+ * Provides a clickable link.
+ *
+ * This pref is a UI placeholder only and will not be stored in the preference
+ * backend.
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The link text.
+ *   'img' - (string) An image file to display before the link.
+ *           DEFAULT: no image displayed
+ *   'url' - (string) The URL to link to (unescaped). Only specify one of
+ *           'url' or 'xurl'.
+ *   'xurl' - (string) The URL to link to (escaped). Only specify one of 'url'
+ *            or 'xurl'.
+ *
+ * 'multienum'
+ * -----------
+ * Provides an enumeration list in the UI that allows for multiple entries
+ * to be selected.
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The description text to use on the options page.
+ *   'escaped' - (boolean) If true, values in 'enum' are already escaped.
+ *               DEFAULT: false
+ *   'enum' - (array) The enumeration list. Keys will be used as the
+ *            prefernce value; values are the text that will be displayed in
+ *            the selection list.
+ *   'value' - (string) A serialized value containing the key(s) selected. All
+ *             keys will be auto-selected in the selection area.
+ *
+ * 'number'
+ * --------
+ * Provides a small textbox to enter a natural number. Values entered for this
+ * preference are automatically converted to a number value.
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The description text to use on the options page.
+ *   'value' - (number) The preference value.
+ *
+ * 'password'
+ * ----------
+ * Provides a textbox for password entry (input characters will not be
+ * displayed to the screen).
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The description text to use on the options page.
+ *   'value' - (string) The preference value.
+ *
+ * 'prefslink'
+ * -----------
+ * Create a link to another preferences page.
+ *
+ * This pref is a UI placeholder only and will not be stored in the preference
+ * backend.
+ *
+ * ADDITIONAL KEYS:
+ *   'app' - (string) The application to link to.
+ *           DEFAULT: current application.
+ *   'desc' - (string) The link text.
+ *   'group' - (string) The preferences group to link to.
+ *   'img' - (string) An image file to display before the link.
+ *           DEFAULT: no image displayed
+ *
+ * 'rawhtml'
+ * ---------
+ * Outputs the raw HTML string to the page.
+ *
+ * This pref is a UI placeholder only and will not be stored in the preference
+ * backend.
+ *
+ * ADDITIONAL KEYS:
+ *   'value' - (string) The raw (already escaped) HTML to output to the page.
+ *
+ * 'special'
+ * ---------
+ * Used as placeholder to indicate that the application will provide both the
+ * UI display code and the subsequent preferences storage.
+ *
+ * This pref is a UI placeholder only and will not be stored in the preference
+ * backend.
+ *
+ * 'text'
+ * ------
+ * Provides a single-line textbox.
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The description text to use on the options page.
+ *   'value' - (string) The preference value.
+ *
+ * 'textarea'
+ * ----------
+ * Provides a multi-line textbox.
+ *
+ * ADDITIONAL KEYS:
+ *   'desc' - (string) The description text to use on the options page.
+ *   'value' - (string) The preference value. Lines should be separated
+ *             with the "\n" character.
  *
  * $Id$
  */
 
+// *** Personal Information preferences ***
+
 $prefGroups['identities'] = array(
     'column' => _("Your Information"),
     'label' => _("Personal Information"),
     'desc' => _("Change the name and address that people see when they read and reply to your emails."),
-    'members' => array('default_identity', 'identityselect', 'deleteidentity',
-                       'id', 'fullname', 'from_addr')
-);
-
-$prefGroups['authentication'] = array(
-    'column' => _("Your Information"),
-    'label' => _("Authentication Credentials"),
-    'desc' => _("Set authentication credentials like user names and passwords for external servers."),
-    'members' => array('credentialsui'),
-);
-
-try {
-    $auth = Horde_Auth::singleton($GLOBALS['conf']['auth']['driver']);
-    if ($auth->hasCapability('update')) {
-        $prefGroups['forgotpass'] = array(
-            'column' => _("Your Information"),
-            'label' => _("Account Password"),
-            'desc' => _("Set options to allow you to reset your password if you ever forget it."),
-            'members' => array('security_question', 'security_answer', 'alternate_email')
-        );
-    }
-} catch (Horde_Exception $e) {}
-
-$prefGroups['language'] = array(
-    'column' => _("Your Information"),
-    'label' => _("Locale and Time"),
-    'desc' => _("Set your preferred language, timezone and date options."),
-    'members' => array('language', 'timezone', 'twentyFour', 'date_format', 'first_week_day')
-);
-
-$prefGroups['categories'] = array(
-    'column' => _("Your Information"),
-    'label' => _("Categories and Labels"),
-    'desc' => _("Manage the list of categories you have to label items with, and colors associated with those categories."),
-    'members' => array('categorymanagement')
-);
-
-$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',
-                       'moz_sidebar', 'menu_view', 'menu_refresh_time',
-                       'widget_accesskey')
-);
-
-$prefGroups['remote'] = array(
-    'column' => _("Other Information"),
-    'label' => _("Remote Servers"),
-    'desc' => _("Set up remote servers that you want to access from your portal."),
-    'url' => 'services/portal/rpcsum.php'
-);
-
-if (!empty($GLOBALS['conf']['facebook']['key']) && !empty($GLOBALS['conf']['facebook']['secret'])) {
-    $prefGroups['facebook'] = array(
-        'column' => _("Other Information"),
-        'label' => _("Facebook Integration"),
-        'desc' => _("Set up integration with your Facebook account."),
-        'url' => 'services/facebook.php'
-    );
-}
-
-if (!empty($GLOBALS['conf']['twitter']['key']) && !empty($GLOBALS['conf']['twitter']['secret'])) {
-    $prefGroups['twitter'] = array(
-        'column' => _("Other Information"),
-        'label' => _("Twitter Integration"),
-        'desc' => _("Set up integration with your Twitter account."),
-        'url' => 'services/twitter.php'
-    );
-}
-
-
-// For alternate IMSP authentication.
-if (!empty($GLOBALS['conf']['imsp']['enabled'])) {
-    $prefGroups['imspauth'] = array(
-        'column' => _("Other Information"),
-        'label' => _("Alternate IMSP Login"),
-        'desc' => _("Use if name/password is different for IMSP server."),
-        'members' => array('imsp_auth_user', 'imsp_auth_pass')
-    );
-}
-
-$prefGroups['syncml'] = array(
-    'column' => _("Other Information"),
-    'label' => _("SyncML"),
-    'desc' => _("Configuration for syncing with PDAs, Smartphones and Outlook."),
-    'url' => 'services/portal/syncml.php',
-    'members' => array()
+    'members' => array(
+        'default_identity', 'identityselect', 'id', 'fullname', 'from_addr'
+    )
 );
 
-// Personal Information preferences
-
 // default identity
 // Set locked to true if you don't want the users to have multiple identities.
 $_prefs['default_identity'] = array(
     'value' => 0,
-    'locked' => false,
     'shared' => true,
     'type' => 'enum',
-    'enum' => (isset($GLOBALS['identity']) && is_object($GLOBALS['identity'])) ? $GLOBALS['identity']->getAll('id') : array(),
-    'desc' => _("Your default identity:"),
+    'desc' => _("Your default identity:")
 );
 
-// identities array
-// Don't change anything here.
+// identities data
 $_prefs['identities'] = array(
+    // value = serialize(array())
     'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit',
+    'shared' => true
 );
 
 // identify email confirmation
 $_prefs['confirm_email'] = array(
+    // value = serialize(array())
     'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit',
+    'shared' => true
 );
 
 // identity selection widget
 $_prefs['identityselect'] = array(
-    'shared' => true,
-    'type' => 'special',
-);
-
-// delete button
-$_prefs['deleteidentity'] = array(
     'type' => 'special',
-    'shared' => true,
+    'shared' => true
 );
 
 // identity name
@@ -218,7 +238,6 @@ $_prefs['deleteidentity'] = array(
 // horde/config/hooks.php.
 $_prefs['id'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
     'type' => 'text',
     'desc' => _("Identity's name:")
@@ -229,7 +248,6 @@ $_prefs['id'] = array(
 // horde/config/hooks.php.
 $_prefs['fullname'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
     'type' => 'text',
     'desc' => _("Your full name:")
@@ -240,32 +258,27 @@ $_prefs['fullname'] = array(
 // horde/config/hooks.php.
 $_prefs['from_addr'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
     'type' => 'text',
     'desc' =>  _("Your From: address:")
 );
 
-// Authentication Options
 
-// credentials
-$_prefs['credentials'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit'
-);
 
-// credentials interface
-$_prefs['credentialsui'] = array(
-    'shared' => true,
-    'type' => 'special',
+// *** Authentication Preferences ***
+
+$prefGroups['forgotpass'] = array(
+    'column' => _("Your Information"),
+    'label' => _("Account Password"),
+    'desc' => _("Set options to allow you to reset your password if you ever forget it."),
+    'members' => array(
+        'security_question', 'security_answer', 'alternate_email'
+    )
 );
 
 // user security question
 $_prefs['security_question'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
     'type' => 'text',
     'desc' => _("Enter a security question which you will be asked if you need to reset your password, e.g. 'what is the name of your pet?':")
@@ -274,7 +287,6 @@ $_prefs['security_question'] = array(
 // user security answer
 $_prefs['security_answer'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
     'type' => 'text',
     'desc' => _("Insert the required answer to the security question:")
@@ -283,35 +295,46 @@ $_prefs['security_answer'] = array(
 // user alternate email
 $_prefs['alternate_email'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
     'type' => 'text',
     'desc' => _("Insert an email address to which you can receive the new password:")
 );
 
+
+
+// *** Locale/Time Preferences ***
+
+$prefGroups['language'] = array(
+    'column' => _("Your Information"),
+    'label' => _("Locale and Time"),
+    'desc' => _("Set your preferred language, timezone and date options."),
+    'members' => array(
+        'language', 'timezone', 'twentyFour', 'date_format', 'first_week_day'
+    )
+);
+
 // user language
+// Language list is dynamically built when prefs screen is displayed
 $_prefs['language'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
-    'type' => 'select',
+    'type' => 'enum',
     'escaped' => true,
     'desc' => _("Select your preferred language:")
 );
 
 // user time zone
+// Timezone list is dynamically built when prefs screen is displayed
 $_prefs['timezone'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
-    'type' => 'select',
+    'type' => 'enum',
     'desc' => _("Your current time zone:")
 );
 
 // time format
 $_prefs['twentyFour'] = array(
     'value' => false,
-    'locked' => false,
     'shared' => true,
     'type' => 'checkbox',
     'desc' => _("Display 24-hour times?")
@@ -320,7 +343,6 @@ $_prefs['twentyFour'] = array(
 // date format
 $_prefs['date_format'] = array(
     'value' => '%x',
-    'locked' => false,
     'shared' => true,
     'type' => 'enum',
     'enum' => array(
@@ -353,61 +375,109 @@ $_prefs['date_format'] = array(
 // what day should be displayed as the first day of the week?
 $_prefs['first_week_day'] = array(
     'value' => '0',
-    'locked' => false,
     'shared' => true,
     'type' => 'enum',
     'desc' => _("Which day would you like to be displayed as the first day of the week?"),
-    'enum' => array('0' => _("Sunday"),
-                    '1' => _("Monday"))
+    'enum' => array(
+        '0' => _("Sunday"),
+        '1' => _("Monday")
+    )
 );
 
-// UI theme
-$_prefs['theme'] = array(
-    'value' => 'silver',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'select',
-    'desc' => _("Select your color scheme.")
+
+
+// *** Categories/Labels Preferences ***
+
+$prefGroups['categories'] = array(
+    'column' => _("Your Information"),
+    'label' => _("Categories and Labels"),
+    'desc' => _("Manage the list of categories you have to label items with, and colors associated with those categories."),
+    'members' => array('categorymanagement')
+);
+
+// UI for category management.
+$_prefs['categorymanagement'] = array(
+    'type' => 'special'
 );
 
 // categories
 $_prefs['categories'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit'
+    'shared' => true
 );
 
 // category colors
 $_prefs['category_colors'] = array(
     'value' => '',
-    'locked' => false,
+    'shared' => true
+);
+
+
+
+// *** Display Options Preferences ***
+
+$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',
+        'moz_sidebar', 'menu_view', 'menu_refresh_time', 'widget_accesskey'
+    )
+);
+
+// what application should we go to after login?
+// Application list is dynamically built when prefs screen is displayed
+$_prefs['initial_application'] = array(
+    'value' => 'horde',
     'shared' => true,
-    'type' => 'implicit'
+    'type' => 'enum',
+    'desc' => sprintf(_("What application should %s display after login?"), $GLOBALS['registry']->get('name'))
 );
 
-// UI for category management.
-$_prefs['categorymanagement'] = array(
-    'type' => 'special'
+// show the last login time of user
+$_prefs['show_last_login'] = array(
+    'value' => true,
+    'shared' => true,
+    'type' => 'checkbox',
+    'desc' => _("Show last login time when logging in?")
+);
+
+// last login time of user
+// value is a serialized array of the UNIX timestamp of the last
+// login, and the host that the last login was from.
+$_prefs['last_login'] = array(
+    // value = serialize(array())
+    'value' => 'a:0:{}',
+    'shared' => true
+);
+
+// UI theme
+// Theme list is dynamically built when prefs screen is displayed
+$_prefs['theme'] = array(
+    'value' => 'silver',
+    'shared' => true,
+    'type' => 'enum',
+    'desc' => _("Select your color scheme.")
 );
 
 $_prefs['summary_refresh_time'] = array(
     'value' => 300,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("Never"),
-                    30 => _("Every 30 seconds"),
-                    60 => _("Every minute"),
-                    300 => _("Every 5 minutes"),
-                    900 => _("Every 15 minutes"),
-                    1800 => _("Every half hour")),
+    'enum' => array(
+        0 => _("Never"),
+        30 => _("Every 30 seconds"),
+        60 => _("Every minute"),
+        300 => _("Every 5 minutes"),
+        900 => _("Every 15 minutes"),
+        1800 => _("Every half hour")
+    ),
     'desc' => _("Refresh Portal View:")
 );
 
 $_prefs['show_sidebar'] = array(
     'value' => true,
-    'locked' => false,
     'shared' => true,
     'type' => 'checkbox',
     'desc' => sprintf(_("Show the %s Menu on the left?"), $GLOBALS['registry']->get('name', 'horde'))
@@ -415,8 +485,6 @@ $_prefs['show_sidebar'] = array(
 
 $_prefs['sidebar_width'] = array(
     'value' => 150,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => sprintf(_("Width of the %s menu on the left:"), $GLOBALS['registry']->get('name', 'horde'))
 );
@@ -433,42 +501,33 @@ $_prefs['moz_sidebar'] = array(
 
 $_prefs['menu_view'] = array(
     'value' => 'both',
-    'locked' => false,
     'shared' => true,
     'type' => 'enum',
-    'enum' => array('text' => _("Text Only"),
-                    'icon' => _("Icons Only"),
-                    'both' => _("Icons with text")),
+    'enum' => array(
+        'text' => _("Text Only"),
+        'icon' => _("Icons Only"),
+        'both' => _("Icons with text")
+    ),
     'desc' => _("Menu mode:")
 );
 
 $_prefs['menu_refresh_time'] = array(
     'value' => 300,
-    'locked' => false,
     'shared' => true,
     'type' => 'enum',
-    'enum' => array(0 => _("Never"),
-                    30 => _("Every 30 seconds"),
-                    60 => _("Every minute"),
-                    120 => _("Every 2 minutes"),
-                    300 => _("Every 5 minutes")),
+    'enum' => array(
+        0 => _("Never"),
+        30 => _("Every 30 seconds"),
+        60 => _("Every minute"),
+        120 => _("Every 2 minutes"),
+        300 => _("Every 5 minutes")
+    ),
     'desc' => _("Refresh Dynamic Menu Elements:")
 );
 
-
-// what application should we go to after login?
-$_prefs['initial_application'] = array(
-    'value' => 'horde',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'select',
-    'desc' => sprintf(_("What application should %s display after login?"), $GLOBALS['registry']->get('name'))
-);
-
 // should we create access keys?
 $_prefs['widget_accesskey'] = array(
     'value' => true,
-    'locked' => false,
     'shared' => true,
     'type' => 'checkbox',
     'desc' => _("Should access keys be defined for most links?")
@@ -476,75 +535,114 @@ $_prefs['widget_accesskey'] = array(
 
 // the layout of the portal page.
 $_prefs['portal_layout'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    // value = serialize(array())
+    'value' => 'a:0:{}'
+);
+
+// *** Remote Servers Preferences ***
+
+$prefGroups['remote'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Remote Servers"),
+    'desc' => _("Set up remote servers that you want to access from your portal."),
+    'members' => array('remotemanagement')
+);
+
+$_prefs['remotemanagement'] = array(
+    'type' => 'special'
 );
 
 // the remote servers.
 $_prefs['remote_summaries'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    // value = serialize(array())
+    'value' => 'a:0:{}'
+);
+
+
+
+// *** Facebook Integration Preferences ***
+
+$prefGroups['facebook'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Facebook Integration"),
+    'desc' => _("Set up integration with your Facebook account."),
+    'members' => array('facebookmanagement')
+);
+
+$_prefs['facebookmanagement'] = array(
+    'type' => 'special'
 );
 
 $_prefs['facebook'] = array(
+    // value = serialize(array())
     'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit'
+    'shared' => true
+);
+
+
+
+// *** Twitter Intergration Preferences ***
+
+$prefGroups['twitter'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Twitter Integration"),
+    'desc' => _("Set up integration with your Twitter account."),
+    'members' => array('twittermanagement')
+);
+
+$_prefs['twittermanagement'] = array(
+    'type' => 'special'
 );
 
 $_prefs['twitter'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    // value = serialize(array())
+    'value' => 'a:0:{}'
 );
 
-// last login time of user
-// value is a serialized array of the UNIX timestamp of the last
-// login, and the host that the last login was from.
-$_prefs['last_login'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit'
+
+
+// *** IMSP Intergration Preferences ***
+
+$prefGroups['imspauth'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Alternate IMSP Login"),
+    'desc' => _("Use if name/password is different for IMSP server."),
+    'members' => array('imsp_auth_user', 'imsp_auth_pass')
 );
 
-// show the last login time of user
-$_prefs['show_last_login'] = array(
-    'value' => true,
-    'locked' => false,
-    'shared' => true,
-    'type' => 'checkbox',
-    'desc' => _("Show last login time when logging in?")
+$_prefs['imsp_auth_user'] = array(
+    'value' => '',
+    'type' => 'text',
+    'desc' => _("Alternate IMSP Username")
+);
+
+$_prefs['imsp_auth_pass'] = array(
+    'value' => '',
+    'type' => 'password',
+    'desc' => _("Alternate IMSP Password")
 );
 
-if (!empty($GLOBALS['conf']['imsp']['enabled'])) {
-    $_prefs['imsp_auth_user'] = array(
-        'value' => '',
-        'locked' => false,
-        'shared' => false,
-        'type' => 'text',
-        'desc' => _("Alternate IMSP Username")
-    );
-
-    $_prefs['imsp_auth_pass'] = array(
-        'value' => '',
-        'locked' => false,
-        'shared' => false,
-        'type' => 'password',
-        'desc' => _("Alternate IMSP Password")
-    );
-}
+
+
+// *** SyncML Preferences ***
+$prefGroups['syncml'] = array(
+    'column' => _("Other Information"),
+    'label' => _("SyncML"),
+    'desc' => _("Configuration for syncing with PDAs, Smartphones and Outlook."),
+    'members' => array('syncmlmanagement')
+);
+
+$_prefs['syncmlmanagement'] = array(
+    'type' => 'special'
+);
+
+
+
+// *** Internal Preferences ***
 
 // last time login tasks were run.
 $_prefs['last_logintasks'] = array(
+    // value = serialize(array())
     'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit'
+    'shared' => true
 );
diff --git a/horde/js/addressbooksprefs.js b/horde/js/addressbooksprefs.js
new file mode 100644 (file)
index 0000000..675032a
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * Provides the javascript for managing addressbooks.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var HordeAddressbooksPrefs = {
+
+    // Variables set by other code: fields
+
+    updateSearchFields: function()
+    {
+        var sv = this._getSelectedValue(false),
+            sf = $('search_fields');
+
+        sf.update('');
+        this.fields.each(function(f) {
+            if (f[0] == sv) {
+                f.slice(1).each(function(o) {
+                    var tmp = new Option(o[1], o[0]);
+                    if (o[2]) {
+                        tmp.selected = true;
+                    }
+                    sf.insert(tmp);
+                });
+            }
+        });
+
+        this.changeSearchFields();
+    },
+
+    _getSelectedValue: function(index)
+    {
+        var ss = $('selected_sources');
+        if (ss) {
+            if (index) {
+                return ss.selectedIndex;
+            }
+            if (ss.selectedIndex >= 0) {
+                return ss.options[ss.selectedIndex].value;
+            }
+            return '';
+        } else {
+            return index ? 0 : this.fields[0][0];
+        }
+    },
+
+    changeSearchFields: function()
+    {
+        var data = [],
+            i = 0,
+            sf = $('search_fields'),
+            sv = this._getSelectedValue(true);
+
+        $A(sf.options).each(function(o) {
+            this.fields[sv][i][2] = o.selected;
+            ++i;
+        }.bind(this));
+
+        this.fields.each(function(f) {
+            var tmp = [ f[0] ];
+            f.slice(1).each(function(o) {
+                if (o[2]) {
+                    tmp.push(o[0]);
+                }
+            });
+            data.push(tmp.join("\t"));
+        });
+        $('search_fields_string').setValue(data.join("\n"));
+    },
+
+    onDomLoad: function()
+    {
+        this.updateSearchFields();
+
+        if ($('search_fields')) {
+            $('search_fields').observe('change', this.changeSearchFields.bind(this));
+        }
+
+        if ($('selected_sources')) {
+            $('selected_sources').observe('change', this.updateSearchFields.bind(this));
+        }
+    }
+
+};
+
+document.observe('dom:loaded', HordeAddressbooksPrefs.onDomLoad.bind(HordeAddressbooksPrefs));
diff --git a/horde/js/alarmprefs.js b/horde/js/alarmprefs.js
new file mode 100644 (file)
index 0000000..c226b90
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Provides the javascript for managing alarms.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var HordeAlarmPrefs = {
+
+    // Variables defaulting to null: pref
+
+    updateParams: function()
+    {
+        [ 'notify', 'mail', 'sms' ].each(function(method) {
+            var p = $(method + 'Params');
+            if (p) {
+                if ($(this.pref).getValue().include(method)) {
+                    p.show();
+                } else {
+                    p.hide();
+                }
+            }
+        }, this);
+    },
+
+    onDomLoad: function()
+    {
+        $(this.pref).observe('change', this.updateParams.bind(this));
+        this.updateParams();
+    }
+
+};
+
+document.observe('dom:load', HordeAlarmPrefs.onDomLoad.bind(HordeAlarmPrefs));
diff --git a/horde/js/categoryprefs.js b/horde/js/categoryprefs.js
new file mode 100644 (file)
index 0000000..2390b89
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Provides the javascript for managing categories.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var HordeCategoryPrefs = {
+
+    // Variables defaulting to null: category_text
+
+    removeCategory: function(e)
+    {
+        var p = $('prefs');
+        $(p.cAction).setValue('remove');
+        $(p.category).setValue(e.element().readAttribute('category'));
+        p.submit();
+    },
+
+    addCategory: function()
+    {
+        var category = window.prompt(this.category_text, ''), p;
+        if (!category.empty()) {
+            p = $('prefs');
+            $(p.cAction).setValue('add');
+            $(p.category).setValue(category);
+            p.submit();
+        }
+    },
+
+    resetBackgrounds: function()
+    {
+        $('prefs').getInputs('text').each(function(i) {
+            if (i.readAttribute('id').startsWith('color_')) {
+                i.setStyle({ backgroundColor: $F(i) });
+            }
+        });
+    },
+
+    colorPicker: function(e)
+    {
+        var elt = e.element(),
+            input = e.element().previous();
+
+        new ColorPicker({
+            color: $F(input),
+            offsetParent: elt,
+            update: [ [ input, 'value' ], [ input, 'background' ] ]
+        });
+
+        e.stop();
+    },
+
+    onDomLoad: function()
+    {
+        $('prefs').observe('reset', function() {
+            this.resetBackgrounds.defer()
+        }.bind(this));
+        $('add_category').observe('click', this.addCategory.bind(this));
+
+        $$('.categoryColorPicker').invoke('observe', 'click', this.colorPicker.bindAsEventListener(this));
+        $$('.categoryDelete').invoke('observe', 'click', this.removeCategory.bindAsEventListener(this));
+    }
+
+};
+
+document.observe('dom:loaded', HordeCategoryPrefs.onDomLoad.bind(HordeCategoryPrefs));
diff --git a/horde/js/rpcprefs.js b/horde/js/rpcprefs.js
new file mode 100644 (file)
index 0000000..fcf1d8f
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * Provides the javascript for managing remote servers.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var HordeRpcPrefs = {
+
+    // Variables defaulting to null: servers
+
+    serverChoice: function(idx)
+    {
+        switch (idx) {
+        case '-1':
+            $('rpc_create').show();
+            $('rpc_change', 'rpc_delete').invoke('hide');
+            $('url', 'user', 'passwd').invoke('setValue', '');
+            break;
+
+        default:
+            $('rpc_create').hide();
+            $('rpc_change', 'rpc_delete').invoke('show');
+            $('url').setValue(this.servers[idx][0]);
+            $('user').setValue(this.servers[idx][1]);
+            $('passwd').setValue('');
+            break;
+        }
+    },
+
+    onDomLoad: function()
+    {
+        $('server').observe('change', function() {
+            this.serverChoice($('server').selectedIndex);
+        }.bind(this));
+        $('rpc_reset').observe('click', function(e) {
+            this.serverChoice('-1');
+            e.stop();
+        }.bindAsEventListener(this));
+
+        if (!this.servers.size()) {
+            $('server').up().hide();
+        }
+
+        this.serverChoice('-1');
+    }
+
+};
+
+document.observe('dom:loaded', HordeRpcPrefs.onDomLoad.bind(HordeRpcPrefs));
diff --git a/horde/js/sourceselect.js b/horde/js/sourceselect.js
new file mode 100644 (file)
index 0000000..0af423f
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * Provides the javascript for managing the source selection widget.
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var HordeSourceSelectPrefs = {
+
+    resetHidden: function()
+    {
+        $('sources').setValue($F('selected_sources').toJSON());
+    },
+
+    moveAction: function(from, to)
+    {
+        $(from).childElements().each(function(c) {
+            if (c.selected) {
+                c.remove();
+                $(to).insert(c);
+            }
+        });
+
+        this.resetHidden();
+    },
+
+    moveSource: function(e, mode)
+    {
+        var sa = $('selected_sources'), sel, tmp;
+
+        if (sa.selectedIndex < 1 || sa.length < 3) {
+            return;
+        }
+
+        // Deselect everything but the first selected item
+        sa.childElements().each(function(s) {
+            if (sel) {
+                s.selected = false;
+            } else if (s.selected) {
+                sel = s;
+            }
+        });
+
+        switch (mode) {
+        case 'down':
+            tmp = sel.next();
+            if (tmp) {
+                sel.remove();
+                tmp.insert({ after: sel });
+            }
+            break;
+
+        case 'up':
+            tmp = sel.previous();
+            if (tmp && tmp.value) {
+                sel.remove();
+                tmp.insert({ before: sel });
+            }
+            break;
+        }
+
+        this.resetHidden();
+        e.stop();
+    },
+
+    onDomLoad: function()
+    {
+        this.resetHidden();
+
+        if ($('unselected_sources')) {
+            $('addsource').observe('click', this.moveAction.bind(this, 'unselected_sources', 'selected_sources'));
+            $('removesource').observe('click', this.moveAction.bind(this, 'selected_sources', 'unselected_sources'));
+            $('moveup').observe('click', this.moveSource.bindAsEventListener(this, 'up'));
+            $('movedown').observe('click', this.moveSource.bindAsEventListener(this, 'down'));
+        }
+    }
+
+};
+
+document.observe('dom:loaded', HordeSourceSelectPrefs.onDomLoad.bind(HordeSourceSelectPrefs));
index 9e113f5..d482d16 100644 (file)
@@ -43,191 +43,49 @@ class Horde_Application extends Horde_Registry_Application
     }
 
     /**
-     * Code to run when viewing prefs for this application.
+     * Code to run on init when viewing prefs for this application.
      *
-     * @param string $group  The prefGroup name.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsInit($group)
+    public function prefsInit($ui)
     {
-        $out = array();
-
-        /* Assign variables for select lists. */
-        if (!$GLOBALS['prefs']->isLocked('timezone')) {
-            $out['timezone_options'] = Horde_Nls::getTimezones();
-            array_unshift($out['timezone_options'], _("Default"));
-        }
-
-        if (!$GLOBALS['prefs']->isLocked('initial_application')) {
-            $out['initial_application_options'] = array();
-            $apps = $GLOBALS['registry']->listApps(array('active'));
-            foreach ($apps as $a) {
-                $perms = $GLOBALS['injector']->getInstance('Horde_Perms');
-                if (file_exists($GLOBALS['registry']->get('fileroot', $a)) &&
-                    (($perms->exists($a) && ($perms->hasPermission($a, Horde_Auth::getAuth(), Horde_Perms::READ) || Horde_Auth::isAdmin())) ||
-                     !$perms->exists($a))) {
-                    $out['initial_application_options'][$a] = $GLOBALS['registry']->get('name', $a);
-                }
-            }
-            asort($out['initial_application_options']);
-        }
-
-        if (!$GLOBALS['prefs']->isLocked('theme')) {
-            $out['theme_options'] = array();
-            $theme_base = $GLOBALS['registry']->get('themesfs', 'horde');
-            $dh = @opendir($theme_base);
-            if (!$dh) {
-                $GLOBALS['notification']->push("Theme directory can't be opened", 'horde.error');
-            } else {
-                while (($dir = readdir($dh)) !== false) {
-                    if ($dir == '.' || $dir == '..') {
-                        continue;
-                    }
-
-                    $theme_name = null;
-                    @include $theme_base . '/' . $dir . '/info.php';
-                    if (!empty($theme_name)) {
-                        $out['theme_options'][$dir] = $theme_name;
-                    }
-                }
-            }
-
-            asort($out['theme_options']);
-        }
+        $GLOBALS['injector']->getInstance('Horde_Prefs_Ui')->prefsInit($ui);
+    }
 
-        return $out;
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    public function prefsSpecial($ui, $item)
+    {
+        return $GLOBALS['injector']->getInstance('Horde_Prefs_Ui')->prefsSpecial($ui, $item);
     }
 
     /**
      * Special preferences handling on update.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
      * @return boolean  True if preference was updated.
      */
-    public function prefsHandle($item, $updated)
+    public function prefsSpecialUpdate($ui, $item)
     {
-        switch ($item) {
-        case 'showsummaryselect':
-            $show_summaries = Horde_Util::getFormData('show_summaries');
-            if (!is_null($show_summaries)) {
-                $GLOBALS['prefs']->setValue('show_summaries', $show_summaries);
-                return true;
-            }
-            break;
-
-        case 'themeselect':
-            $theme = Horde_Util::getFormData('theme');
-            if (!is_null($theme)) {
-                $GLOBALS['prefs']->setValue('theme', $theme);
-                return true;
-            }
-            break;
-
-        case 'categorymanagement':
-            $cManager = new Horde_Prefs_CategoryManager();
-
-            /* Always save colors of all categories. */
-            $colors = array();
-            $categories = $cManager->get();
-            foreach ($categories as $category) {
-                if ($color = Horde_Util::getFormData('color_' . md5($category))) {
-                    $colors[$category] = $color;
-                }
-            }
-            if ($color = Horde_Util::getFormData('color_' . md5('_default_'))) {
-                $colors['_default_'] = $color;
-            }
-            if ($color = Horde_Util::getFormData('color_' . md5('_unfiled_'))) {
-                $colors['_unfiled_'] = $color;
-            }
-            $cManager->setColors($colors);
-
-            $action = Horde_Util::getFormData('cAction');
-            $category = Horde_Util::getFormData('category');
-
-            switch ($action) {
-            case 'add':
-                $cManager->add($category);
-                break;
-
-            case 'remove':
-                $cManager->remove($category);
-                break;
-
-            default:
-                /* Save button. */
-                $updated = true;
-                Horde::addInlineScript(
-                    'if (window.opener && window.name) window.close();', 'javascript'
-                );
-            }
-            break;
-
-        case 'credentialsui':
-            $credentials = Horde_Util::getFormData('credentials');
-            if (!is_null($credentials)) {
-                $GLOBALS['prefs']->setValue('credentials', serialize($credentials));
-                return true;
-            }
-            break;
-        }
-
-        return $updated;
+        return $GLOBALS['injector']->getInstance('Horde_Prefs_Ui')->prefsSpecialUpdate($ui, $item);
     }
 
     /**
-     * Do anything that we need to do as a result of certain preferences
-     * changing.
+     * Called when preferences are changed.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsCallback()
+    public function prefsCallback($ui)
     {
-        $need_reload = false;
-        $old_sidebar = $GLOBALS['prefs']->getValue('show_sidebar');
-
-        if ($GLOBALS['prefs']->isDirty('language')) {
-            if ($GLOBALS['prefs']->isDirty('language')) {
-                Horde_Nls::setLanguageEnvironment($GLOBALS['prefs']->getValue('language'));
-                foreach ($GLOBALS['registry']->listAPIs() as $api) {
-                    if ($GLOBALS['registry']->hasMethod($api . '/changeLanguage')) {
-                        $GLOBALS['registry']->call($api . '/changeLanguage');
-                    }
-                }
-            }
-
-            $need_reload = true;
-        } else {
-            /* Do reload on change of any of these variables. */
-            $need_reload = (
-                $GLOBALS['prefs']->isDirty('sidebar_width') ||
-                $GLOBALS['prefs']->isDirty('theme') ||
-                $GLOBALS['prefs']->isDirty('menu_view') ||
-                $GLOBALS['prefs']->isDirty('menu_refresh_time'));
-        }
-
-        if ($GLOBALS['prefs']->isDirty('show_sidebar')) {
-            $need_reload = true;
-            $old_sidebar = !$old_sidebar;
-        }
-
-        if ($need_reload) {
-            $url = $GLOBALS['registry']->get('webroot', 'horde');
-            if (substr($url, -1) != '/') {
-                $url .= '/';
-            }
-
-            $url = str_replace('&amp;', '&', Horde::url(Horde_Util::addParameter($url . 'index.php', array('force_sidebar' => true, 'url' => Horde::selfUrl(true, false, true)), null, false)));
-
-            /* If the old view was with sidebar, need to reload the entire
-             * frame. */
-            if ($old_sidebar) {
-                Horde::addInlineScript(
-                    'window.parent.frames.location = ' . Horde_Serialize::serialize($url, Horde_Serialize::JSON, Horde_Nls::getCharset()) . ';'
-                );
-            } else {
-                Horde::redirect($url);
-            }
-        }
+        $GLOBALS['injector']->getInstance('Horde_Prefs_Ui')->prefsCallback($ui);
     }
 
 }
diff --git a/horde/lib/Prefs/Ui.php b/horde/lib/Prefs/Ui.php
new file mode 100644 (file)
index 0000000..082c9c2
--- /dev/null
@@ -0,0 +1,665 @@
+<?php
+/**
+ * Horde-specific prefs handling.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author  Michael Slusarz <slusarz@horde.org>
+ * @package Horde
+ */
+class Horde_Prefs_Ui
+{
+    /**
+     * Code to run on init when viewing prefs for this application.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    public function prefsInit($ui)
+    {
+        global $conf, $prefs, $registry;
+
+        switch ($ui->group) {
+        case 'display':
+            if (!$prefs->isLocked('initial_application')) {
+                $out = array();
+                $apps = $registry->listApps(array('active'));
+                foreach ($apps as $a) {
+                    $perms = $GLOBALS['injector']->getInstance('Horde_Perms');
+                    if (file_exists($registry->get('fileroot', $a)) &&
+                        (($perms->exists($a) && ($perms->hasPermission($a, Horde_Auth::getAuth(), Horde_Perms::READ) || Horde_Auth::isAdmin())) ||
+                         !$perms->exists($a))) {
+                        $out[$a] = $registry->get('name', $a);
+                    }
+                }
+                asort($out);
+                $ui->override['initial_application'] = $out;
+            }
+
+            if (!$prefs->isLocked('theme')) {
+                $out = array();
+                $theme_base = $registry->get('themesfs', 'horde');
+                $dh = @opendir($theme_base);
+                if (!$dh) {
+                    $GLOBALS['notification']->push(_("Theme directory can't be opened"), 'horde.error');
+                } else {
+                    while (($dir = readdir($dh)) !== false) {
+                        if ($dir == '.' || $dir == '..') {
+                            continue;
+                        }
+
+                        $theme_name = null;
+                        @include $theme_base . '/' . $dir . '/info.php';
+                        if (!empty($theme_name)) {
+                            $out[$dir] = $theme_name;
+                        }
+                    }
+                }
+
+                asort($out);
+                $ui->override['theme'] = $out;
+            }
+            break;
+
+        case 'language':
+            if (!$prefs->isLocked('language')) {
+                $ui->override['language'] = Horde_Nls::$config['languages'];
+                array_unshift($ui->override['language'], _("Default"));
+            }
+
+            if (!$prefs->isLocked('timezone')) {
+                $ui->override['timezone'] = Horde_Nls::getTimezones();
+                array_unshift($ui->override['timezone'], _("Default"));
+            }
+            break;
+
+        case 'remote':
+            Horde::addScriptFile('rpcprefs.js', 'horde');
+            $ui->nobuttons = true;
+            break;
+        }
+
+        /* Hide appropriate prefGroups. */
+        try {
+            Horde_Auth::singleton($conf['auth']['driver'])->hasCapability('update');
+        } catch (Horde_Exception $e) {
+            $ui->suppressGroups[] = 'forgotpass';
+        }
+
+        if (empty($conf['facebook']['enabled']) ||
+            empty($conf['facebook']['key']) ||
+            empty($conf['facebook']['secret'])) {
+            $ui->suppressGroups[] = 'facebook';
+        }
+
+        if (empty($conf['twitter']['enabled']) ||
+            empty($conf['twitter']['key']) ||
+            empty($conf['twitter']['secret'])) {
+            $ui->suppressGroups[] = 'twitter';
+        }
+
+        if (empty($conf['imsp']['enabled'])) {
+            $ui->suppressGroups[] = 'imspauth';
+        }
+    }
+
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    public function prefsSpecial($ui, $item)
+    {
+        switch ($item) {
+        case 'categorymanagement':
+            return $this->_categoryManagement($ui);
+
+        case 'identityselect':
+            return $this->_identitySelect($ui);
+
+        case 'remotemanagement':
+            return $this->_remoteManagement($ui);
+
+        case 'syncmlmanagement':
+            return $this->_syncmlManagement($ui);
+        }
+
+        return '';
+    }
+
+    /**
+     * Special preferences handling on update.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return boolean  True if preference was updated.
+     */
+    public function prefsSpecialUpdate($ui, $item)
+    {
+        switch ($item) {
+        case 'categorymanagement':
+            return $this->_updateCategoryManagement($ui);
+
+        case 'identityselect':
+            return false;
+
+        case 'remotemanagement':
+            $this->_updateRemoteManagement($ui);
+            break;
+
+        case 'syncmlmanagement':
+            $this->_updateSyncmlManagement($ui);
+            break;
+        }
+
+        return false;
+    }
+
+    /**
+     * Called when preferences are changed.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    public function prefsCallback($ui)
+    {
+        global $prefs, $registry;
+
+        $need_reload = false;
+        $old_sidebar = $prefs->getValue('show_sidebar');
+
+        if ($prefs->isDirty('language')) {
+            if ($prefs->isDirty('language')) {
+                Horde_Nls::setLanguageEnvironment($prefs->getValue('language'));
+                foreach ($registry->listAPIs() as $api) {
+                    if ($registry->hasMethod($api . '/changeLanguage')) {
+                        $registry->call($api . '/changeLanguage');
+                    }
+                }
+            }
+
+            $need_reload = true;
+        } else {
+            /* Do reload on change of any of these variables. */
+            $need_reload = (
+                $prefs->isDirty('sidebar_width') ||
+                $prefs->isDirty('theme') ||
+                $prefs->isDirty('menu_view') ||
+                $prefs->isDirty('menu_refresh_time')
+            );
+        }
+
+        if ($prefs->isDirty('show_sidebar')) {
+            $need_reload = true;
+            $old_sidebar = !$old_sidebar;
+        }
+
+        if ($need_reload) {
+            $url = Horde::applicationUrl('index.php')->setRaw(true)->add(array(
+                'force_sidebar' => true,
+                'url' => strval(Horde::selfUrl(true, false, true))
+            ));
+
+            /* If the old view was with sidebar, need to reload the entire
+             * frame. */
+            if ($old_sidebar) {
+                Horde::addInlineScript(
+                    'window.parent.frames.location = ' . Horde_Serialize::serialize($url, Horde_Serialize::JSON, Horde_Nls::getCharset()) . ';'
+                );
+            } else {
+                Horde::redirect($url);
+            }
+        }
+    }
+
+    /**
+     * Create code for category management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _categoryManagement($ui)
+    {
+        Horde::addScriptFile('categoryprefs.js', 'horde');
+        Horde::addScriptFile('colorpicker.js', 'horde');
+        Horde::addInlineScript(array(
+            'HordeAlarmPrefs.category_text = ' . Horde_Serialize::serialize(_("Enter a name for the new category:"), Horde_Serialize::JSON)
+        ));
+
+        $cManager = new Horde_Prefs_CategoryManager();
+        $categories = $cManager->get();
+        $colors = $cManager->colors();
+        $fgcolors = $cManager->fgColors();
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        if (!$GLOBALS['prefs']->isLocked('category_colors')) {
+            $t->set('picker_img',  Horde::img('colorpicker.png', _("Color Picker")));
+        }
+        $t->set('delete_img',  Horde::img('delete.png'));
+
+        // Default Color
+        $color = isset($colors['_default_'])
+            ? htmlspecialchars($colors['_default_'])
+            : '#FFFFFF';
+        $fgcolor = isset($fgcolors['_default_'])
+            ? htmlspecialchars($fgcolors['_default_'])
+            : '#000000';
+        $color_b = 'color_' . hash('md5', '_default_');
+
+        $t->set('default_color', $color);
+        $t->set('default_fgcolor', $fgcolor);
+        $t->set('default_label', Horde::label($color_b, _("Default Color")));
+        $t->set('default_id', $color_b);
+
+        // Unfiled Color
+        $color = isset($colors['_unfiled_'])
+            ? htmlspecialchars($colors['_unfiled_'])
+            : '#FFFFFF';
+        $fgcolor = isset($fgcolors['_unfiled_'])
+            ? htmlspecialchars($fgcolors['_unfiled_'])
+            : '#000000';
+        $color_b = 'color_' . hash('md5', '_unfiled_');
+
+        $t->set('unfiled_color', $color);
+        $t->set('unfiled_fgcolor', $fgcolor);
+        $t->set('unfiled_label', Horde::label($color_b, _("Unfiled")));
+        $t->set('unfiled_id', $color_b);
+
+        $entries = array();
+        foreach ($categories as $name) {
+            $color = isset($colors[$name])
+                ? htmlspecialchars($colors[$name])
+                : '#FFFFFF';
+            $fgcolor = isset($fgcolors[$name])
+                ? htmlspecialchars($fgcolors[$name])
+                : '#000000';
+            $color_b = 'color_' . hash('md5', $name);
+
+            $entries[] = array(
+                'color' => $color,
+                'fgcolor' => $fgcolor,
+                'label' => Horde::label($color_b, ($name == '_default_' ? _("Default Color") : htmlspecialchars($name))),
+                'id' => $color_b,
+                'name' => htmlspecialchars($name)
+            );
+        }
+        $t->set('categories', $entries);
+
+        return $t->fetch(HORDE_TEMPLATES . '/prefs/category.html');
+    }
+
+    /**
+     * Create code for identity selection.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _identitySelect($ui)
+    {
+        $identity = Horde_Prefs_Identity::singleton($ui->app == 'horde' ? null : array($ui->app, $ui->app));
+        $default_identity = $identity->getDefault();
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        if ($GLOBALS['prefs']->isLocked('default_identity')) {
+            $t->set('locked', true);
+            $t->set('default_identity', intval($default_identity));
+        } else {
+            $t->set('label', Horde::label('identity', _("Select the identity you want to change:")));
+
+            $identities = $identity->getAll('id');
+            $members = $this->getChangeablePrefs('identities');
+
+            $entry = $js = array();
+
+            for ($i = 0, $icnt = count($identities); $i < $icnt; ++$i) {
+                $entry[] = array(
+                    'i' => $i,
+                    'label' => htmlspecialchars($identities[$i]),
+                    'sel' => ($i == $default_identity)
+                );
+
+                $tmp = array();
+                foreach ($members as $member) {
+                    if (($member == 'default_identity') ||
+                        !empty($this->prefs[$member]['locked']) ||
+                        empty($this->prefs[$member]['type']) ||
+                        in_array($this->prefs[$member]['type'], array('link', 'special'))) {
+                        continue;
+                    }
+
+                    $val = $identity->getValue($member, $i);
+                    switch ($this->prefs[$member]['type']) {
+                    case 'checkbox':
+                        $val2 = $val ? 'true' : 'false';
+                        break;
+
+                    case 'number':
+                        $val2 = intval($val);
+                        break;
+
+                    case 'textarea':
+                        if (is_array($val)) {
+                            $val = implode("\n", $val);
+                        }
+                        // Fall-through
+
+                    default:
+                        $val2 = Horde_String::convertCharset($val, Horde_Nls::getCharset(), 'UTF-8');
+                    }
+
+                    $tmp[] = array(
+                        $member,
+                        $this->prefs[$member]['type'],
+                        $val2
+                    );
+                }
+
+                $js[] = $tmp;
+            }
+
+            $t->set('entry', $entry);
+
+            Horde::addScriptFile('identityselect.js', 'horde');
+            Horde::addInlineScript(array(
+                'IdentitySelect.newChoice()'
+            ), 'dom');
+            Horde::addInlineScript(array(
+                'IdentitySelect.identities = ' . Horde_Serialize::serialize($js, Horde_Serialize::JSON),
+                'IdentitySelect.deleteurl = ' . Horde_Serialize::serialize(strval(Horde::selfUrl(true)->setRaw(true)->add('actionID', 'delete_identity')), Horde_Serialize::JSON)
+            ));
+        }
+
+        return $t->fetch(HORDE_TEMPLATES . '/prefs/identityselect.html');
+    }
+
+    /**
+     * Create code for remote server management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _remoteManagement($ui)
+    {
+        $rpc_servers = @unserialize($GLOBALS['prefs']->getValue('remote_summaries'));
+        if (!is_array($rpc_servers)) {
+            $rpc_servers = array();
+        }
+
+        $js = $serverlist = array();
+        foreach ($rpc_servers as $key => $val) {
+            $js[] = array($val['url'], $val['user']);
+            $serverlist[] = array(
+                'i' => $key,
+                'l' => htmlspecialchars($val['url'])
+            );
+        }
+
+        Horde::addInlineScript(array(
+            'HordeRpcPrefs.servers = ' . Horde_Serialize::serialize($js, Horde_Serialize::JSON)
+
+        ));
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('serverlabel', Horde::label('server', _("Your remote servers:")));
+        $t->set('serverlist', $serverlist);
+        $t->set('urllabel', Horde::label('url', _("Remote URL (http://www.example.com/horde):")));
+        $t->set('userlabel', Horde::label('user', _("Username:")));
+        $t->set('passwdlabel', Horde::label('passwd', _("Password:")));
+
+        return $t->fetch(HORDE_TEMPLATES . '/prefs/rpc.html');
+    }
+
+    /**
+     * Create code for SyncML management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _syncmlManagement($ui)
+    {
+        $devices = SyncML_Backend::factory('Horde')->getUserAnchors(Horde_Auth::getAuth());
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $devices = array();
+        $selfurl = $ui->selfUrl()->add('deleteanchor', 1);
+
+        foreach ($devices as $device => $anchors) {
+            foreach ($anchors as $anchor) {
+                $devices[] = array(
+                    'anchor' => htmlspecialchars($anchor['syncml_clientanchor']),
+                    'db' => htmlspecialchars($anchor['syncml_db']),
+                    'delete' => $selfurl->copy()->add(array(
+                        'db' => $anchor['syncml_db'],
+                        'deviceid' => $device
+                    )),
+                    'device' => htmlspecialchars($device),
+                    'time' => strftime($GLOBALS['prefs']->getValue('date_format') . ' %H:%M', $anchor['syncml_serveranchor'])
+                );
+            }
+        }
+        $t->set('devices', $devices);
+
+        return $t->fetch(HORDE_TEMPLATES . '/prefs/syncml.html');
+    }
+
+    /**
+     * Update category related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return boolean  True if preferences were updated.
+     */
+    protected function _updateCategoryManagement($ui)
+    {
+        $cManager = new Horde_Prefs_CategoryManager();
+
+        /* Always save colors of all categories. */
+        $colors = array();
+        $categories = $cManager->get();
+        foreach ($categories as $category) {
+            if ($color = $ui->vars->get('color_' . hash('md5', $category))) {
+                $colors[$category] = $color;
+            }
+        }
+        if ($color = $ui->vars->get('color_' . hash('md5', '_default_'))) {
+            $colors['_default_'] = $color;
+        }
+        if ($color = $ui->vars->get('color_' . hash('md5', '_unfiled_'))) {
+            $colors['_unfiled_'] = $color;
+        }
+        $cManager->setColors($colors);
+
+        switch ($ui->vars->cAction) {
+        case 'add':
+            $cManager->add($ui->vars->category);
+            break;
+
+        case 'remove':
+            $cManager->remove($ui->vars->category);
+            break;
+
+        default:
+            /* Save button. */
+            Horde::addInlineScript(array(
+                'if (window.opener && window.name) window.close();'
+            ));
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Update remote servers related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateRemoteManagement($ui)
+    {
+        global $notification, $prefs;
+
+        $rpc_servers = @unserialize($prefs->getValue('remote_summaries'));
+        if (!is_array($rpc_servers)) {
+            $rpc_servers = array();
+        }
+
+        if ($ui->vars->rpc_change || $ui->vars->rpc_create) {
+            $tmp = array(
+                'passwd' => $ui->vars->passwd,
+                'url' => $ui->vars->url,
+                'user' => $ui->vars->user
+            );
+
+            if ($ui->vars->rpc_change) {
+                $rpc_servers[$ui->vars->server] = $tmp;
+            } else {
+                $rpc_servers[] = $tmp;
+            }
+
+            $prefs->setValue('remote_summaries', serialize($rpc_servers));
+            $notification->push(sprintf(_("The server \"%s\" has been saved."), $ui->vars->url), 'horde.success');
+        } elseif ($ui->vars->rpc_delete) {
+            if ($ui->vars->server == -1) {
+                $notification->push(_("You must select an server to be deleted."), 'horde.warning');
+            } else {
+                $notification->push(sprintf(_("The server \"%s\" has been deleted."), $rpc_servers[$ui->vars->server]['url']), 'horde.success');
+
+                $deleted_server = $rpc_servers[$ui->vars->server]['url'];
+                unset($rpc_servers[$ui->vars->server]);
+                $prefs->setValue('remote_summaries', serialize(array_values($rpc_servers)));
+
+                $chosenColumns = explode(';', $prefs->getValue('show_summaries'));
+                if ($chosenColumns != array('')) {
+                    $newColumns = array();
+                    foreach ($chosenColumns as $chosenColumn) {
+                        $chosenColumn = explode(',', $chosenColumn);
+                        $remote = explode('|', $chosenColumn[0]);
+                        if (count($remote) != 3 || $remote[2] == $deleted_server) {
+                            $newColumns[] = implode(',', $chosenColumn);
+                        }
+                    }
+                    $prefs->setValue('show_summaries', implode(';', $newColumns));
+                }
+            }
+        }
+    }
+
+    /**
+     * Update SyncML related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateSyncmlManagement($ui)
+    {
+        $backend = SyncML_Backend::factory('Horde');
+
+        if ($ui->vars->deleteanchor) {
+            $res = $backend->removeAnchor(Horde_Auth::getAuth(), $ui->vars->deviceid, $ui->vars->db);
+            if ($res instanceof PEAR_Error) {
+                $GLOBALS['notification']->push(_("Error deleting synchronization session:") . ' ' . $res->getMessage(), 'horde.error');
+            } else {
+                $GLOBALS['notification']->push(sprintf(_("Deleted synchronization session for device \"%s\" and database \"%s\"."), $ui->vars->deviceid, $ui->vars->db), 'horde.success');
+            }
+        } elseif ($ui->vars->deleteall) {
+            $res = $backend->removeAnchor(Horde_Auth::getAuth());
+            if ($res instanceof PEAR_Error) {
+                $GLOBALS['notification']->push(_("Error deleting synchronization sessions:") . ' ' . $res->getMessage(), 'horde.error');
+            } else {
+                $GLOBALS['notification']->push(_("All synchronization sessions deleted."), 'horde.success');
+            }
+        }
+    }
+
+/*
+            try {
+                $this->prefGroups['identities']['members'] = array_keys(array_flip(array_merge(
+                    $res['prefGroups']['identities']['members'],
+                    $this->prefGroups['identities']['members']
+                )));
+                $this->prefs = Horde_Array::array_merge_recursive_overwrite($res['_prefs'], $this->prefs);
+            } catch (Horde_Exception $e) {}
+            case 'update_prefs':
+                $from_addresses = $identity->getAll('from_addr');
+                $current_from = $identity->getValue('from_addr');
+                if ($prefs->isLocked('default_identity')) {
+                    $default = $identity->getDefault();
+                } else {
+                    $default = $this->vars->default_identity;
+                    $id = $this->vars->identity;
+                    if ($id == -1) {
+                        $id = $identity->add();
+                    } elseif ($id == -2) {
+                        $this->prefGroups['identities']['members'] = array('default_identity');
+                    }
+                    $identity->setDefault($id);
+                }
+
+                $this->_save = $identity;
+
+                if (!$this->_handleForm($this->getChangeablePrefs($this->group))) {
+                    return;
+                }
+
+                $new_from = $identity->getValue('from_addr');
+                if (!empty($conf['user']['verify_from_addr']) &&
+                    $current_from != $new_from &&
+                    !in_array($new_from, $from_addresses)) {
+                    try {
+                        $result = $identity->verifyIdentity($id, empty($current_from) ? $new_from : $current_from);
+                        if ($result instanceof Notification_Event) {
+                            $notification->push($result, 'horde.message');
+                        }
+                    } catch (Horde_Exception $e) {
+                        $notification->push(_("The new from address can't be verified, try again later: ") . $e->getMessage(), 'horde.error');
+                        Horde::logMessage($e, 'ERR');
+                    }
+                    break;
+                }
+
+                $identity->setDefault($default);
+                $identity->save();
+                break;
+            case 'delete_identity':
+                $id = intval($this->vars->id);
+                $deleted_identity = $identity->delete($id);
+                unset($this->prefs['default_identity']['enum'][$id]);
+                $notification->push(sprintf(_("The identity \"%s\" has been deleted."), $deleted_identity[0]['id']), 'horde.success');
+                break;
+
+            case 'change_default_identity':
+                $default_identity = $identity->setDefault(intval($this->vars->id));
+                $identity->save();
+                $notification->push(_("Your default identity has been changed."), 'horde.success');
+                break;
+            }
+            break;
+
+            if (is_callable(array($this->_save, 'verify'))) {
+                try {
+                    $this->_save->verify();
+                } catch (Exception $e) {
+                    $notification->push($e, 'horde.error');
+                }
+            }
+
+        //    $ui->override['default_identity'] = $identity->getAll('id');
+        //
+*/
+}
index 544f963..475c3e7 100644 (file)
@@ -13,9 +13,9 @@
 require_once dirname(__FILE__) . '/../lib/Application.php';
 Horde_Registry::appInit('horde');
 
-if (empty($GLOBALS['conf']['facebook']['enabled']) ||
-    empty($GLOBALS['conf']['facebook']['key']) ||
-    empty($GLOBALS['conf']['facebook']['secret'])) {
+if (empty($conf['facebook']['enabled']) ||
+    empty($conf['facebook']['key']) ||
+    empty($conf['facebook']['secret'])) {
 
     $horde_url = Horde::url($registry->get('webroot', 'horde') . '/index.php');
     header('Location: ' . $horde_url);
@@ -23,8 +23,8 @@ if (empty($GLOBALS['conf']['facebook']['enabled']) ||
 }
 
 // Facebook key and secret
-$apikey = $GLOBALS['conf']['facebook']['key'];
-$secret = $GLOBALS['conf']['facebook']['secret'];
+$apikey = $conf['facebook']['key'];
+$secret = $conf['facebook']['secret'];
 
 // Create required objects
 $context = array('http_client' => new Horde_Http_Client(),
@@ -40,14 +40,14 @@ if ($token = Horde_Util::getFormData('auth_token')) {
     try {
         $haveSession = $facebook->auth->validateSession(true, true);
     } catch (Horde_Service_Facebook_Exception $e) {
-        $GLOBALS['notify']->push(_("Temporarily unable to connect with Facebook, Please try again."), 'horde.alert');
+        $notification->push(_("Temporarily unable to connect with Facebook, Please try again."), 'horde.alert');
     }
     if ($haveSession) {
         // Remember in user prefs
         $sid =  $facebook->auth->getSessionKey();
         $uid = $facebook->auth->getUser();
         $prefs->setValue('facebook', serialize(array('uid' => $uid, 'sid' => $sid)));
-        $GLOBALS['notification']->push(_("Succesfully connected your Facebook account."), 'horde.success');
+        $notification->push(_("Succesfully connected your Facebook account."), 'horde.success');
     }
 } else {
     // Require the rest of the actions to be POST only since following them
@@ -196,10 +196,9 @@ if (!empty($haveSession)) {
 }
 
 // Start rendering the prefs page
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_Ui::generateHeader('horde', null, 'facebook', $chunk);
-$csslink = $GLOBALS['registry']->get('themesuri', 'horde') . '/facebook.css';
-echo '<link href="' . $csslink . '" rel="stylesheet" type="text/css" />';
+// TODO: This won't work - prefs handling must be moved to the new
+// preferences framework.
+//$csslink = $registry->get('themesuri', 'horde') . '/facebook.css';
 
 if (!empty($haveSession)) {
     // If we are here, we have a valid session. Facebook strongly suggests to
@@ -212,7 +211,7 @@ if (!empty($haveSession)) {
     try {
         $user_info = $facebook->fql->run($fql);
     } catch (Horde_Service_Facebook_Exception $e) {
-        $GLOBALS['notify']->push(_("Temporarily unable to connect with Facebook, Please try again."), 'horde.alert');
+        $notify->push(_("Temporarily unable to connect with Facebook, Please try again."), 'horde.alert');
     }
     // url to revoke authorization
     $url = Horde_Util::addParameter(Horde::selfUrl(true), array('action' => 'revokeApplication'));
@@ -287,6 +286,3 @@ if (!empty($haveSession)) {
         echo sprintf(_("Login to Facebook and authorize the %s application:"), $registry->get('name'))
             . '<a class="fbbutton" href="' . $url . '">Facebook</a>';
 }
-// Need to close the prefs form (opened by the Horde_Prefs_Ui)
-echo '</form>';
-require HORDE_TEMPLATES . '/common-footer.inc';
diff --git a/horde/services/portal/rpcsum.php b/horde/services/portal/rpcsum.php
deleted file mode 100644 (file)
index dedd79d..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-/**
- * Copyright 2001-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Jan Schneider <jan@horde.org>
- */
-
-require_once dirname(__FILE__) . '/../../lib/Application.php';
-Horde_Registry::appInit('horde');
-
-$rpc_servers = @unserialize($prefs->getValue('remote_summaries'));
-if (!is_array($rpc_servers)) {
-    $rpc_servers = array();
-}
-
-$actionID = Horde_Util::getFormData('actionID');
-
-// Handle clients without javascript.
-if (is_null($actionID)) {
-    if (Horde_Util::getPost('edit')) {
-        $actionID = 'edit';
-    } elseif (Horde_Util::getPost('save')) {
-        $actionID = 'save';
-    } elseif (Horde_Util::getPost('delete')) {
-        $actionID = 'delete';
-    }
-}
-
-/* Run through the action handlers */
-switch ($actionID) {
-case 'save':
-    if (($to_edit = Horde_Util::getFormData('edit_server')) == null) {
-        $to_edit = count($rpc_servers);
-        $rpc_servers[] = array();
-    }
-    $rpc_servers[$to_edit]['url']    = Horde_Util::getFormData('url');
-    $rpc_servers[$to_edit]['user']   = Horde_Util::getFormData('user');
-    $rpc_servers[$to_edit]['passwd'] = Horde_Util::getFormData('passwd');
-    $prefs->setValue('remote_summaries', serialize($rpc_servers));
-    $prefs->store();
-    $notification->push(sprintf(_("The server \"%s\" has been saved."), $rpc_servers[$to_edit]['url']), 'horde.success');
-    break;
-
-case 'delete':
-    $to_delete = Horde_Util::getFormData('server');
-    if ($to_delete != -1) {
-        $deleted_server = $rpc_servers[$to_delete]['url'];
-        $server_list = array();
-        for ($i = 0; $i < count($rpc_servers); $i++) {
-            if ($i == $to_delete) {
-                continue;
-            }
-            $server_list[] = $rpc_servers[$i];
-        }
-        $prefs->setValue('remote_summaries', serialize($server_list));
-        $chosenColumns = explode(';', $prefs->getValue('show_summaries'));
-        if ($chosenColumns != array('')) {
-            $newColumns = array();
-            foreach ($chosenColumns as $chosenColumn) {
-                $chosenColumn = explode(',', $chosenColumn);
-                $remote = explode('|', $chosenColumn[0]);
-                if (count($remote) != 3 || $remote[2] == $deleted_server) {
-                    $newColumns[] = implode(',', $chosenColumn);
-                }
-            }
-            $prefs->setValue('show_summaries', implode(';', $newColumns));
-        }
-        $prefs->store();
-        $rpc_servers = $server_list;
-        $notification->push(sprintf(_("The server \"%s\" has been deleted."), $deleted_server), 'horde.success');
-    } else {
-        $notification->push(_("You must select an server to be deleted."), 'horde.warning');
-    }
-    break;
-}
-
-/* Show the header. */
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_Ui::generateHeader('horde', null, 'remote', $chunk);
-
-require HORDE_TEMPLATES . '/rpcsum/rpcsum.inc';
-if (!$chunk) {
-    require HORDE_TEMPLATES . '/common-footer.inc';
-}
diff --git a/horde/services/portal/syncml.php b/horde/services/portal/syncml.php
deleted file mode 100644 (file)
index cb79aee..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-/**
- * Copyright 2005-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Karsten Fourmont <karsten@horde.org>
- */
-
-require_once dirname(__FILE__) . '/../../lib/Application.php';
-Horde_Registry::appInit('horde');
-
-$backend = SyncML_Backend::factory('Horde');
-
-$actionID = Horde_Util::getFormData('actionID');
-switch ($actionID) {
-case 'deleteanchor':
-    $deviceid = Horde_Util::getFormData('deviceid');
-    $db = Horde_Util::getFormData('db');
-    $result = $backend->removeAnchor(Horde_Auth::getAuth(), $deviceid, $db);
-    if (is_a($result, 'PEAR_Error')) {
-        $notification->push(_("Error deleting synchronization session:")
-                            . ' ' . $result->getMessage(),
-                            'horde.error');
-    } else {
-        $notification->push(sprintf(_("Deleted synchronization session for device \"%s\" and database \"%s\"."),
-                                    $deviceid, $db),
-                            'horde.success');
-    }
-    break;
-
-case 'deleteall':
-    $result = $backend->removeAnchor(Horde_Auth::getAuth());
-    if (is_a($result, 'PEAR_Error')) {
-        $notification->push(_("Error deleting synchronization sessions:")
-                            . ' ' . $result->getMessage(),
-                            'horde.error');
-    } else {
-        $notification->push(_("All synchronization sessions deleted."),
-                            'horde.success');
-    }
-    break;
-}
-
-$devices = $backend->getUserAnchors(Horde_Auth::getAuth());
-
-/* Show the header. */
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_UI::generateHeader('horde', null, 'syncml', $chunk);
-
-require HORDE_TEMPLATES . '/syncml/syncml.inc';
-if (!$chunk) {
-    require HORDE_TEMPLATES . '/common-footer.inc';
-}
index 5556d63..967e6af 100644 (file)
@@ -1,6 +1,12 @@
 <?php
 /**
- * Preferences UI page.
+ * Preferences/Options UI page.
+ *
+ * URL Parameters
+ * --------------
+ * 'actionID' - (string) Action ID.
+ * 'app' - (string) The current Horde application.
+ * 'group' - (string) The current preferences group.
  *
  * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
  *
  * @category Horde
  */
 
-function _loadPrefsConfig($app, $merge = false)
-{
-    try {
-        $res = Horde::loadConfiguration('prefs.php', array('prefGroups', '_prefs'), $app);
-    } catch (Horde_Exception $e) {
-        $res = array('prefGroups' => array(), '_prefs' => array());
-    }
-
-    if ($merge) {
-        try {
-            $GLOBALS['prefGroups']['identities']['members'] = array_keys(array_flip(array_merge(
-                $res['prefGroups']['identities']['members'],
-                $GLOBALS['prefGroups']['identities']['members'])));
-            $GLOBALS['_prefs'] = Horde_Array::array_merge_recursive_overwrite($res['_prefs'], $GLOBALS['_prefs']);
-        } catch (Horde_Exception $e) {}
-    } else {
-        $GLOBALS['prefGroups'] = $res['prefGroups'];
-        $GLOBALS['_prefs'] = $res['_prefs'];
-    }
-}
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
 Horde_Registry::appInit('horde');
 
-/* Figure out which application we're setting preferences for. */
-$app = Horde_Util::getFormData('app', Horde_Prefs_Ui::getDefaultApp());
-$appbase = realpath($registry->get('fileroot', $app));
-
-/* See if we have a preferences group set. */
-$group = Horde_Util::getFormData('group');
-
-/* See if only a page body was requested. */
-$chunk = Horde_Util::nonInputVar('chunk');
-
-/* Load $app's base environment. */
-$registry->pushApp($app);
-
-/* Set title. */
-$title = sprintf(_("Options for %s"), $registry->get('name'));
-
-/* Load identity here - Identity object may be needed in app's prefs.php. */
-if ($group == 'identities') {
-    $identity = Horde_Prefs_Identity::singleton($app == 'horde' ? null : array($app, $app));
-}
-
-/* Get ActionID. */
-$actionID = Horde_Util::getFormData('actionID');
-
-/* Run prefs_ui init code, if available. */
-if ($registry->hasAppMethod($app, 'prefsInit')) {
-    $result = $registry->callAppMethod($app, 'prefsInit', array('args' => array($group)));
-    if (!empty($result)) {
-        extract($result);
-    }
-}
-
-/* Load $app's preferences, if any. */
-$prefGroups = array();
-_loadPrefsConfig($app);
-
-/* See if this group has a custom URL. */
-if ($group && !empty($prefGroups[$group]['url'])) {
-    $pref_url = $prefGroups[$group]['url'];
-    $filename = $appbase . '/' . $pref_url;
-    if (file_exists($filename)) {
-        require $filename;
-        return;
-    }
-    throw new Horde_Exception('Incorrect url value (' . $pref_url . ') for preferences group ' . $group . ' for app ' . $app);
-}
-
-/* If there's only one prefGroup, just show it. */
-if (empty($group) && count($prefGroups) == 1) {
-    $group = array_keys($prefGroups);
-    $group = array_pop($group);
-}
-
-if ($group == 'identities') {
-    if ($app != 'horde') {
-        _loadPrefsConfig('horde', true);
-    }
-
-    switch ($actionID) {
-    case 'update_prefs':
-        $from_addresses = $identity->getAll('from_addr');
-        $current_from = $identity->getValue('from_addr');
-        if ($prefs->isLocked('default_identity')) {
-            $default = $identity->getDefault();
-        } else {
-            $default = Horde_Util::getPost('default_identity');
-            $id = Horde_Util::getPost('identity');
-            if ($id == -1) {
-                $id = $identity->add();
-            } elseif ($id == -2) {
-                $prefGroups['identities']['members'] = array('default_identity');
-            }
-            $identity->setDefault($id);
-        }
-
-        if (!Horde_Prefs_Ui::handleForm($group, $identity, $app, $prefGroups, $_prefs)) {
-            break;
-        }
-
-        $new_from = $identity->getValue('from_addr');
-        if (!empty($conf['user']['verify_from_addr']) &&
-            $current_from != $new_from &&
-            !in_array($new_from, $from_addresses)) {
-            try {
-                $result = $identity->verifyIdentity($id, empty($current_from) ? $new_from : $current_from);
-                if ($result instanceof Notification_Event) {
-                    $notification->push($result, 'horde.message');
-                }
-            } catch (Horde_Exception $e) {
-                $notification->push(_("The new from address can't be verified, try again later: ") . $e->getMessage(), 'horde.error');
-                Horde::logMessage($e, 'ERR');
-            }
-            break;
-        }
-
-        $identity->setDefault($default);
-        $identity->save();
-        unset($prefGroups);
-
-        _loadPrefsConfig($app);
-        if ($app != 'horde') {
-            _loadPrefsConfig('horde', true);
-        }
-        break;
-
-    case 'delete_identity':
-        $id = (int)Horde_Util::getFormData('id');
-        $deleted_identity = $identity->delete($id);
-        unset($_prefs['default_identity']['enum'][$id]);
-        $notification->push(sprintf(_("The identity \"%s\" has been deleted."), $deleted_identity[0]['id']), 'horde.success');
-        break;
-
-    case 'change_default_identity':
-        $default_identity = $identity->setDefault(Horde_Util::getFormData('id'));
-        $identity->save();
-        $notification->push(_("Your default identity has been changed."),
-                            'horde.success');
-        break;
-    }
-} elseif ($group &&
-          ($actionID == 'update_prefs') &&
-          Horde_Prefs_Ui::handleForm($group, $prefs, $app, $prefGroups, $_prefs)) {
-    _loadPrefsConfig($app);
-
-    if (count($prefGroups) == 1 && empty($group)) {
-        $group = array_keys($prefGroups);
-        $group = array_pop($group);
-    }
-}
+$prefs_ui = new Horde_Core_Prefs_Ui(Horde_Variables::getDefaultVariables());
 
-/* Show the UI. */
-Horde_Prefs_Ui::generateUI($app, $prefGroups, $_prefs, $group, $chunk);
+/* Handle form submission. */
+$prefs_ui->handleForm();
 
-if (!$chunk) {
-    require $registry->get('templates', 'horde') . '/common-footer.inc';
-}
+/* Generate the UI. */
+$prefs_ui->generateUI();
index 805149d..f505353 100644 (file)
 require_once dirname(__FILE__) . '/../lib/Application.php';
 Horde_Registry::appInit('horde');
 
-if (empty($GLOBALS['conf']['twitter']['enabled'])) {
+if (empty($conf['twitter']['enabled'])) {
     $horde_url = Horde::url($registry->get('webroot', 'horde') . '/index.php');
     header('Location: ' . $horde_url);
     exit;
 }
 
-/* Create a cache object for the twitter client */
-$cache = $injector->getInstance('Horde_Cache');
-
 /* Using OAuth or Http Basic? */
-if (!empty($GLOBALS['conf']['twitter']['key']) && !empty($GLOBALS['conf']['twitter']['secret'])) {
+if (!empty($conf['twitter']['key']) && !empty($conf['twitter']['secret'])) {
     /* Keys - these are obtained when registering for the service */
-    $consumer_key = $GLOBALS['conf']['twitter']['key'];
-    $consumer_secret = $GLOBALS['conf']['twitter']['secret'];
+    $consumer_key = $conf['twitter']['key'];
+    $consumer_secret = $conf['twitter']['secret'];
 
     /* Parameters required for the Horde_Oauth_Consumer */
-    $params = array('key' => $consumer_key,
-                    'secret' => $consumer_secret,
-                    'requestTokenUrl' => Horde_Service_Twitter::REQUEST_TOKEN_URL,
-                    'authorizeTokenUrl' => Horde_Service_Twitter::USER_AUTHORIZE_URL,
-                    'accessTokenUrl' => Horde_Service_Twitter::ACCESS_TOKEN_URL,
-                    'signatureMethod' => new Horde_Oauth_SignatureMethod_HmacSha1());
+    $params = array(
+        'key' => $consumer_key,
+        'secret' => $consumer_secret,
+        'requestTokenUrl' => Horde_Service_Twitter::REQUEST_TOKEN_URL,
+        'authorizeTokenUrl' => Horde_Service_Twitter::USER_AUTHORIZE_URL,
+        'accessTokenUrl' => Horde_Service_Twitter::ACCESS_TOKEN_URL,
+        'signatureMethod' => new Horde_Oauth_SignatureMethod_HmacSha1()
+    );
 
     /* Create the Consumer */
     $oauth = new Horde_Oauth_Consumer($params);
 
     /* Create the Twitter client */
-    $twitter = new Horde_Service_Twitter(array('oauth' => $oauth, 'cache' => $cache));
+    $twitter = new Horde_Service_Twitter(array(
+        'cache' => $injector->getInstance('Horde_Cache'),
+        'oauth' => $oauth
+    ));
 
     /* See if we have an existing token for the current user */
     $token = unserialize($prefs->getValue('twitter'));
@@ -49,10 +51,13 @@ if (!empty($GLOBALS['conf']['twitter']['key']) && !empty($GLOBALS['conf']['twitt
         $auth_token = new Horde_Oauth_Token($token['key'], $token['secret']);
         $twitter->auth->setToken($auth_token);
     }
-} elseif (!empty($_SESSION['horde']['twitterblock']['username']) && !empty($_SESSION['horde']['twitterblock']['password'])) {
-    $twitter = new Horde_Service_Twitter(array('username' => $_SESSION['horde']['twitterblock']['username'],
-                                               'password' => $_SESSION['horde']['twitterblock']['password'],
-                                               'cache' => $cache));
+} elseif (!empty($_SESSION['horde']['twitterblock']['username']) &&
+          !empty($_SESSION['horde']['twitterblock']['password'])) {
+    $twitter = new Horde_Service_Twitter(array(
+        'cache' => $injector->getInstance('Horde_Cache'),
+        'password' => $_SESSION['horde']['twitterblock']['password'],
+        'username' => $_SESSION['horde']['twitterblock']['username']
+    ));
 }
 
 /* See if we are here for any actions */
@@ -63,6 +68,7 @@ case 'revokeInfinite':
     $prefs->setValue('twitter', 'a:0:{}');
     echo '<script type="text/javascript">location.href="' . Horde::selfUrl(false) . '?app=horde&nomenu=0&group=twitter";</script>';
     exit;
+
 case 'updateStatus':
     $result = $twitter->statuses->update(Horde_Util::getPost('statusText'), Horde_Util::getPost('inReplyTo', ''));
     header('Content-Type: application/json');
@@ -76,8 +82,7 @@ if (!empty($auth_token)) {
 } elseif (!empty($_SESSION['twitter_request_secret'])) {
      /* No existing auth token, maybe we are in the process of getting it? */
     try {
-        $auth_token = $twitter->auth->getAccessToken(new Horde_Controller_Request_Http(),
-                                                     $_SESSION['twitter_request_secret']);
+        $auth_token = $twitter->auth->getAccessToken(new Horde_Controller_Request_Http(), $_SESSION['twitter_request_secret']);
     } catch (Horde_Service_Twitter_Exception $e) {
         echo '<div class="fberrorbox">' . sprintf(_("Error connecting to Twitter: %s Details have been logged for the administrator."), $e->getMessage()) . '</div>';
         echo '</form>';
@@ -118,10 +123,7 @@ if (!empty($auth_token)) {
 }
 
 // Start rendering the prefs page
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_Ui::generateHeader('horde', null, 'twitter', $chunk);
-$csslink = $GLOBALS['registry']->get('themesuri', 'horde') . '/facebook.css';
-echo '<link href="' . $csslink . '" rel="stylesheet" type="text/css" />';
+//$csslink = $registry->get('themesuri', 'horde') . '/facebook.css';
 
 /* Could not find a valid auth token, and we are not in the process of getting one */
 if (empty($profile)) {
@@ -147,6 +149,3 @@ if (empty($profile)) {
     echo '<div class="fbbluebox">' . sprintf(_("%s can interact with your Twitter account."), $registry->get('name'));
     echo ' <div class="fbaction"><input type="submit" class="fbbutton" value="' . _("Disable") . '" onclick="document.prefs.actionID.value=\'revokeInfinite\'; return true" /></div></div>';
 }
-
-echo '</form>';
-require HORDE_TEMPLATES . '/common-footer.inc';
index 10699f5..e364235 100644 (file)
@@ -1,15 +1,12 @@
-<div id="menu">
- <div class="leftFloat">
 <?php
-if (!(isset($menu) && ($menu instanceof Horde_Menu))) {
-    $menu = new Horde_Menu();
-    $status = $GLOBALS['registry']->get('status', 'horde');
-    if ($GLOBALS['registry']->getApp() == 'horde' &&
-        $status != 'notoolbar' && $status != 'hidden' && $status != 'inactive') {
-        $menu->add(Horde::applicationUrl('services/portal/'), _("_Home"), 'horde.png', Horde_Themes::img(null, 'horde'));
+    if (!(isset($menu) && ($menu instanceof Horde_Menu))) {
+        $menu = new Horde_Menu();
+        if (($GLOBALS['registry']->getApp() == 'horde') &&
+            !in_array($GLOBALS['registry']->get('status', 'horde'), array('notoolbar', 'hidden', 'inactive'))) {
+            $menu->add(Horde::applicationUrl('services/portal/'), _("_Home"), 'horde.png', Horde_Themes::img(null, 'horde'));
+        }
     }
-}
-echo $menu->render();
 ?>
- </div>
+<div id="menu">
+ <div class="leftFloat"><?php echo $menu->render(); ?></div>
 </div>
diff --git a/horde/templates/prefs/addressbooks.html b/horde/templates/prefs/addressbooks.html
new file mode 100644 (file)
index 0000000..72602a6
--- /dev/null
@@ -0,0 +1,21 @@
+<p>
+<if:selected>
+ <gettext>Click on one of your selected address books and then select all fields to search.</gettext>
+<else:selected>
+ <gettext>Select all fields to search when expanding addresses.</gettext>
+</else:selected></if:selected>
+</p>
+
+<div>
+ <gettext>To select multiple fields, hold down the Control (PC) or Command (Mac) while clicking.</gettext>
+</div>
+
+<input type="hidden" name="search_fields_string" id="search_fields_string" />
+<table>
+ <tr>
+  <td>
+   <label for="search_fields" class="hidden"><gettext>Fields to search</gettext></label>
+   <select id="search_fields" name="search_fields" multiple="multiple" size="5"></select>
+  </td>
+ </tr>
+</table>
diff --git a/horde/templates/prefs/alarm.html b/horde/templates/prefs/alarm.html
new file mode 100644 (file)
index 0000000..442c2b2
--- /dev/null
@@ -0,0 +1,47 @@
+<div>
+ <tag:desc /> 
+ <tag:helplink />
+</div>
+
+<div>
+ <select id="<tag:pref />" multiple="multiple" name="<tag:pref />[]">
+<loop:select_list>
+  <option<if:select_list.s> selected="selected"</if:select_list.s> value="<tag:select_list.v />"><tag:select_list.l /></option>
+</loop:select_list>
+ </select>
+</div>
+
+<loop:param_list>
+<div id="<tag:param_list.method />Params">
+<loop:param_list.param>
+<if:param_list.param.text>
+ <tag:param_list.param.label />
+ <br />
+ <input type="text" id="<tag:param_list.param.name />" name="<tag:param_list.param.name />" value="<tag:param_list.param.value />" />
+ <br />
+</if:param_list.param.text>
+<if:param_list.param.bool>
+ <input type="checkbox" id="<tag:param_list.param.name />" name="<tag:param_list.param.name />"<if:param_list.param.checked> checked="checked"</if:param_list.param.checked> />
+ <br />
+ <tag:param_list.param.label />
+ <br />
+</if:param_list.param.bool>
+<if:param_list.param.sound>
+ <ul class="sound-list">
+  <li>
+   <label><input type="radio" name="<tag:param_list.param.name />" value=""<if:param_list.param.checked> checked="checked"</if:param_list.param.checked> /><gettext>No Sound</gettext></label>
+ </li>
+<loop:sounds>
+ <li>
+  <label>
+   <input type="radio" name="<tag:param_list.param.name />" value="<tag:param_list.param.val />"<if:param_list.param.c> checked="checked"</if:param_list.param.c> />
+   <tag:param_list.param.val />
+  </label>
+  <embed autostart="false" src="<tag:param_list.param.uri />" />
+ </li>
+</loop:sounds>
+</ul>
+</if:param_list.param.sound>
+</loop:param_list.param>
+</div>
+</loop:param_list>
diff --git a/horde/templates/prefs/alarm.inc b/horde/templates/prefs/alarm.inc
deleted file mode 100644 (file)
index f9c42cc..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-Horde::addScriptFile('prototype.js', 'horde');
-$alarm_pref = unserialize($prefs->getValue($pref));
-$selected = array_keys($alarm_pref);
-$methods = Horde_Alarm::notificationMethods();
-echo Horde::label($pref, $_prefs[$pref]['desc']) ?>&nbsp;<?php echo $helplink ?><br />
-<select id="<?php echo $pref ?>" multiple="multiple" name="<?php echo $pref ?>[]" onchange="updateParams()">
-<?php foreach ($methods as $method => $params): ?>
-<option<?php if (in_array($method, $selected)) echo ' selected="selected"' ?> value="<?php echo $method ?>"><?php echo $params['__desc'] ?></option>
-<?php endforeach; ?>
-</select>
-<?php foreach ($methods as $method => $params): if (count($params) > 1): ?>
-<div id="<?php echo $method ?>Params">
-<?php foreach ($params as $name => $param): if (substr($name, 0, 2) == '__') continue; ?>
-
-<?php if ($param['type'] == 'text'): ?>
-<?php echo Horde::label($pref . '_' . $name, $param['desc']) ?><br />
-<input type="text" id="<?php echo $pref . '_' . $name ?>" name="<?php echo $pref . '_' . $name ?>" value="<?php echo empty($alarm_pref[$method][$name]) ? '' : htmlspecialchars($alarm_pref[$method][$name]) ?>" /><br />
-
-<?php elseif ($param['type'] == 'boolean'): ?>
-<input type="checkbox" id="<?php echo $pref . '_' . $name ?>" name="<?php echo $pref . '_' . $name ?>"<?php if (!empty($alarm_pref[$method][$name])) echo ' checked="checked"' ?> />
-<?php echo Horde::label($pref . '_' . $name, $param['desc']) ?><br />
-
-<?php elseif ($param['type'] == 'sound'): $current_sound = !empty($alarm_pref[$method][$name]) ? $alarm_pref[$method][$name] : ''; ?>
-<ul class="sound-list">
- <li><label><input type="radio" name="<?php echo $pref . '_' . $name ?>" value=""<?php if (!$current_sound) echo ' checked="checked"' ?> /> <?php echo _("No Sound") ?></label></li>
-<?php foreach (Horde_Themes::soundList() as $key => $val): ?>
- <li>
-  <label>
-   <input type="radio" name="<?php echo $pref . '_' . $name ?>" value="<?php echo htmlspecialchars($key) ?>"<?php if ($current_sound == $key) echo ' checked="checked"' ?> />
-   <?php echo htmlspecialchars($key) ?>
-  </label>
-  <embed autostart="false" src="<?php echo htmlspecialchars($val->uri) ?>" />
- </li>
-<?php endforeach; ?>
-</ul>
-
-<?php endif; endforeach; ?>
-</div>
-<?php endif; endforeach; ?>
-<script type="text/javascript">
-function updateParams()
-{
-    ['notify','mail','sms'].each(function(method) {
-        if ($(method + 'Params')) {
-            if (Form.Element.getValue('<?php echo $pref ?>').include(method)) {
-                Element.show(method + 'Params');
-            } else {
-                Element.hide(method + 'Params');
-            }
-        }
-    });
-}
-updateParams();
-</script>
diff --git a/horde/templates/prefs/app.html b/horde/templates/prefs/app.html
new file mode 100644 (file)
index 0000000..2a95e29
--- /dev/null
@@ -0,0 +1,25 @@
+<form method="get" name="appswitch" id="appswitch" action="<tag:action />">
+ <tag:forminput />
+ <div class="header">
+  <span class="smallheader rightFloat">
+   <select id="app" name="app" onchange="document.appswitch.submit();">
+    <option value=""><gettext>Edit Options for</gettext>:</option>
+<if:horde>
+    <option value="" disabled="disabled">- - - - - - - - -</option>
+    <option value="horde"><gettext>Global Options</gettext></option>
+    <option value="" disabled="disabled">- - - - - - - - -</option>
+</if:horde>
+<loop:apps>
+    <option value="<tag:apps.v />"><tag:apps.l /></option>
+</loop:apps>
+   </select>
+   <input class="button" type="submit" onclick="return document.appswitch.app.selectedIndex != 0;" value="<gettext>Go</gettext>" />
+  </span>
+  <span>
+   <tag:header />
+  </span>
+  <br class="clear" />
+ </div>
+</form>
+
+<br class="spacer" />
diff --git a/horde/templates/prefs/app.inc b/horde/templates/prefs/app.inc
deleted file mode 100644 (file)
index 3d579ea..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<form method="get" name="appswitch" id="appswitch" action="<?php echo Horde::getServiceLink('options') ?>">
-<?php echo Horde_Util::formInput() ?>
-<div class="header">
- <span class="smallheader rightFloat">
-  <?php echo Horde::label('app', _("Edit options for:")) ?>
-  <select id="app" name="app" onchange="document.appswitch.submit();">
-   <option value=""><?php echo _("Choose Application:") ?></option>
-<?php if (!empty($apps['horde'])): ?>
-   <option value="" disabled="disabled">- - - - - - - - -</option>
-   <option value="horde"><?php echo _("Global Options") ?></option>
-   <option value="" disabled="disabled">- - - - - - - - -</option>
-<?php endif; ?>
-<?php foreach (array_diff($apps, array('horde')) as $key => $val): ?>
-   <option value="<?php echo htmlspecialchars($key) ?>"><?php echo htmlspecialchars($val) ?></option>
-<?php endforeach; ?>
-  </select>
-  <input class="button" type="submit" onclick="return document.appswitch.app.selectedIndex != 0;" value="<?php echo _("Go") ?>" />
- </span>
- <span>
-<?php if ($registry->getApp() == 'horde'): ?>
-  <?php echo _("Global Options") ?>
-<?php else: ?>
-  <?php printf(_("Options for %s"), $GLOBALS['registry']->get('name')) ?>
-<?php endif; ?>
- </span>
- <br class="clear" />
-</div>
-</form>
-<br class="spacer" />
diff --git a/horde/templates/prefs/begin.html b/horde/templates/prefs/begin.html
new file mode 100644 (file)
index 0000000..74ddd69
--- /dev/null
@@ -0,0 +1,21 @@
+<form method="post" id="prefs" name="prefs" action="<tag:action />">
+<tag:forminput />
+<input type="hidden" name="actionID" value="update_prefs" />
+<input type="hidden" name="group" value="<tag:group />" />
+<input type="hidden" id="prefs_app" name="app" value="<tag:app />" />
+
+<div class="header">
+<if:prev>
+ <ul>
+  <li>
+   <a href="<tag:prev />">&lt;&lt; <tag:prevlabel /></a>
+   |
+   <a href="<tag:next />"><tag:nextlabel /> &gt;&gt;</a>
+  </li>
+ </ul>
+</if:prev>
+ <tag:label />
+ <br class="clear" />
+</div>
+
+<div class="prefsContainer item">
diff --git a/horde/templates/prefs/begin.inc b/horde/templates/prefs/begin.inc
deleted file mode 100644 (file)
index ffe3481..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<form method="post" id="prefs" name="prefs" action="<?php echo Horde::selfUrl() ?>">
-<?php echo Horde_Util::formInput() ?>
-<input type="hidden" name="actionID" value="update_prefs" />
-<input type="hidden" name="group" value="<?php echo htmlspecialchars($group) ?>" />
-<input type="hidden" id="prefs_app" name="app" value="<?php echo htmlspecialchars($app) ?>" />
-
-<div class="header">
- <?php Horde_Prefs_Ui::generateNavigationCell($app, $group) ?>
- <?php echo htmlspecialchars($prefGroups[$group]['label']) ?>
- <br class="clear" />
-</div>
-
-<div class="prefsContainer item">
diff --git a/horde/templates/prefs/category.html b/horde/templates/prefs/category.html
new file mode 100644 (file)
index 0000000..f36e8a6
--- /dev/null
@@ -0,0 +1,42 @@
+<input name="cAction" value="" type="hidden" />
+<input name="category" value="" type="hidden" />
+<input type="button" class="button" id="add_category" value="<gettext>New Category</gettext>" />
+
+<table>
+ <tr>
+  <td style="background-color:<tag:default_color />;color:<tag:default_fgcolor />">
+   <strong><tag:default_label /></strong>
+  </td>
+  <td>
+<if:picker_img>
+   <input size="7" style="background:<tag:default_color />;color:<tag:default_fgcolor />" id="<tag:default_id />" name="<tag:default_id />" value="<tag:default_color />" />
+   <a href="#" class="categoryColorPicker"><tag:picker_img /></a>
+</if:picker_img>
+  </td>
+ </tr>
+ <tr>
+  <td style="background-color:<tag:unfiled_color />;color:<tag:unfiled_fgcolor />">
+   <strong><tag:unfiled_label /></strong>
+  </td>
+  <td>
+<if:picker_img>
+   <input size="7" style="background:<tag:unfiled_color />;color:<tag:unfiled_fgcolor />" id="<tag:unfiled_id />" name="<tag:unfiled_id />" value="<tag:unfiled_color />" />
+   <a href="#" class="categoryColorPicker"><tag:picker_img /></a>
+</if:picker_img>
+  </td>
+ </tr>
+<loop:categories>
+ <tr>
+  <td style="background-color:<tag:categories.color />;color:<tag:categories.fgcolor />">
+   <strong><tag:categories.label /></strong>
+  </td>
+  <td>
+<if:picker_img>
+   <input size="7" style="background:<tag:categories.color />;color:<tag:categories.fgcolor />" id="<tag:categories.id />" name="<tag:categories.id />" value="<tag:categories.color />" />
+   <a href="#" class="categoryColorPicker"><tag:picker_img /></a>
+</if:picker_img>
+   <a href="#" class="categoryDelete" category="<tag:categories.name />"><tag:delete_img /></a>
+  </td>
+ </tr>
+</loop:categories>
+</table>
diff --git a/horde/templates/prefs/categorymanagement.inc b/horde/templates/prefs/categorymanagement.inc
deleted file mode 100644 (file)
index 4cec818..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-Horde::addScriptFile('prototype.js', 'horde');
-Horde::addScriptFile('colorpicker.js', 'horde');
-$cManager = new Horde_Prefs_CategoryManager();
-$categories = $cManager->get();
-$colors = $cManager->colors();
-$fgcolors = $cManager->fgColors();
-
-// Default Color
-$color = isset($colors['_default_']) ? $colors['_default_'] : '#FFFFFF';
-$fgcolor = isset($fgcolors['_default_']) ? $fgcolors['_default_'] : '#000000';
-$color_b = 'color_' . hash('md5', '_default_');
-?>
-<script type="text/javascript">
-function removeCategory(category)
-{
-    var p = $('prefs');
-    $(p.cAction).setValue('remove');
-    $(p.category).setValue(category);
-    p.submit();
-}
-
-function addCategory()
-{
-    var category = window.prompt('<?php echo addslashes(_("Please enter a name for the new category:")) ?>', ''), p;
-    if (category != null && category != '') {
-        p = $('prefs');
-        $(p.cAction).setValue('add');
-        $(p.category).setValue(category);
-        p.submit();
-    }
-}
-
-function resetBackgrounds()
-{
-    $('prefs').getInputs('text').each(function(i) {
-        if (i.readAttribute('id').startsWith('color_')) {
-            i.setStyle({ backgroundColor: $F(i) });
-        }
-    });
-}
-
-document.observe('dom:loaded', function() {
-    $('prefs').observe('reset', function() { resetBackgrounds.defer() });
-});
-</script>
-<input name="cAction" value="" type="hidden" />
-<input name="category" value="" type="hidden" />
-<input type="button" class="button" value="<?php echo _("New Category") ?>" onclick="addCategory();" />
-<table>
- <tr>
-  <td style="background-color:<?php echo htmlspecialchars($color) ?>; color:<?php echo $fgcolor ?>"><strong><?php echo Horde::label($color_b, _("Default Color")) ?></strong></td>
-  <td>
-   <?php if (!$prefs->isLocked('category_colors')): ?>
-    <input size="7" style="background:<?php echo htmlspecialchars($color) ?>; color:<?php echo $fgcolor ?>" id="<?php echo $color_b ?>" name="<?php echo $color_b ?>" value="<?php echo htmlspecialchars($color) ?>" />
-    <a href="#" onclick="new ColorPicker({ color: $F('<?php echo $color_b ?>'), offsetParent: Event.element(event), update: [['<?php echo $color_b ?>', 'value'], ['<?php echo $color_b ?>', 'background']] }); return false;">
-    <?php echo Horde::img('colorpicker.png', _("Color Picker"), 'height="16"') ?></a>
-   <?php endif; ?>
-  </td>
- </tr>
-<?php
-// Unfiled Color
-$color = isset($colors['_unfiled_']) ? $colors['_unfiled_'] : '#FFFFFF';
-$fgcolor = isset($fgcolors['_unfiled_']) ? $fgcolors['_unfiled_'] : '#000000';
-$color_b = 'color_' . hash('md5', '_unfiled_');
-?>
- <tr>
-  <td style="background-color:<?php echo htmlspecialchars($color) ?>; color:<?php echo $fgcolor ?>"><strong><?php echo Horde::label($color_b, _("Unfiled")) ?></strong></td>
-  <td>
-   <?php if (!$prefs->isLocked('category_colors')): ?>
-    <input size="7" style="background:<?php echo htmlspecialchars($color) ?>; color:<?php echo $fgcolor ?>" id="<?php echo $color_b ?>" name="<?php echo $color_b ?>" value="<?php echo htmlspecialchars($color) ?>" />
-    <a href="#" onclick="new ColorPicker({ color: $F('<?php echo $color_b ?>'), offsetParent: Event.element(event), update: [['<?php echo $color_b ?>', 'value'], ['<?php echo $color_b ?>', 'background']] }); return false;">
-    <?php echo Horde::img('colorpicker.png', _("Color Picker"), 'height="16"') ?></a>
-   <?php endif; ?>
-  </td>
- </tr>
-<?php
-foreach ($categories as $name):
-    $color = isset($colors[$name]) ? $colors[$name] : '#FFFFFF';
-    $fgcolor = isset($fgcolors[$name]) ? $fgcolors[$name] : '#000000';
-    $color_b = 'color_' . hash('md5', $name);
-?>
- <tr>
-  <td style="background-color:<?php echo htmlspecialchars($color) ?>; color:<?php echo $fgcolor ?>"><strong><?php echo Horde::label($color_b, ($name == '_default_' ? _("Default Color") : htmlspecialchars($name))) ?></strong></td>
-  <td>
-   <?php if (!$prefs->isLocked('category_colors')): ?>
-    <input size="7" style="background:<?php echo htmlspecialchars($color) ?>; color:<?php echo $fgcolor ?>" id="<?php echo $color_b ?>" name="<?php echo $color_b ?>" value="<?php echo htmlspecialchars($color) ?>" />
-    <a href="#" onclick="new ColorPicker({ color: $F('<?php echo $color_b ?>'), offsetParent: Event.element(event), update: [['<?php echo $color_b ?>', 'value'], ['<?php echo $color_b ?>', 'background']] }); return false;">
-    <?php echo Horde::img('colorpicker.png', _("Color Picker"), 'height="16"') ?></a>
-    <?php endif; ?>
-    <a href="#" onclick="removeCategory(decodeURIComponent('<?php echo rawurlencode(Horde_String::convertCharset($name, Horde_Nls::getCharset(), 'UTF-8')) ?>')); return false;"><?php echo Horde::img('delete.png') ?></a>
-  </td>
- </tr>
-<?php endforeach; ?>
-</table>
diff --git a/horde/templates/prefs/checkbox.html b/horde/templates/prefs/checkbox.html
new file mode 100644 (file)
index 0000000..7ec9ef4
--- /dev/null
@@ -0,0 +1,5 @@
+<div>
+ <input type="checkbox" class="checkbox" id="<tag:pref />" name="<tag:pref />"<if:checked> checked="checked"</if:checked> />
+ <tag:desc />
+ <tag:helplink />
+</div>
diff --git a/horde/templates/prefs/checkbox.inc b/horde/templates/prefs/checkbox.inc
deleted file mode 100644 (file)
index 9ff62d1..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<div>
- <input type="checkbox" class="checkbox" id="<?php echo $pref ?>" name="<?php echo $pref ?>"<?php echo $prefs->getValue($pref) ? ' checked="checked"' : '' ?> />
- <?php echo Horde::label($pref, $_prefs[$pref]['desc']) ?>
- <?php echo $helplink ?>
-</div>
diff --git a/horde/templates/prefs/credentialsui.inc b/horde/templates/prefs/credentialsui.inc
deleted file mode 100644 (file)
index d8a30c0..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-Horde_Prefs_Credentials::showUi();
diff --git a/horde/templates/prefs/deleteidentity.inc b/horde/templates/prefs/deleteidentity.inc
deleted file mode 100644 (file)
index 1ef76be..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php if (!$prefs->isLocked('default_identity')): ?>
-<?php
-    echo Horde::wrapInlineScript(array(
-        'IdentitySelect.deleteurl = ' . Horde_Serialize::serialize(strval(Horde::selfUrl(true)->setRaw(true)->add('actionID', 'delete_identity')), Horde_Serialize::JSON)
-    ));
-?>
-<div>
- <p>
-  <input id="deleteidentity" type="button" class="button" value="<?php echo _("Delete selected identity") ?>" />
- </p>
-</div>
-<?php endif; ?>
diff --git a/horde/templates/prefs/end.html b/horde/templates/prefs/end.html
new file mode 100644 (file)
index 0000000..52fd4c5
--- /dev/null
@@ -0,0 +1,11 @@
+  <p>
+<if:buttons>
+   <input type="submit" class="button" value="<gettext>Save Options</gettext>" />
+   <input type="reset" class="button" value="<gettext>Undo Changes</gettext>" />
+</if:buttons>
+<if:prefgroups>
+   <input type="submit" id="prefs_return" name="prefs_return" class="button" value="<gettext>Return to Options</gettext>" />
+</if:prefgroups>
+  </p>
+ </div>
+</form>
diff --git a/horde/templates/prefs/end.inc b/horde/templates/prefs/end.inc
deleted file mode 100644 (file)
index 9cd9c34..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
- <p>
-<?php if (!Horde_Util::nonInputVar('prefsui_no_save')): ?>
-  <input type="submit" class="button" value="<?php echo _("Save Options") ?>" />&nbsp;
-  <input type="reset" class="button" value="<?php echo _("Undo Changes") ?>" />&nbsp;
-<?php endif; ?>
-<?php if (count($prefGroups) > 1): ?>
-  <input type="button" id="prefs_return" class="button" value="<?php echo _("Return to Options") ?>" onclick="document.prefs.actionID.value=0; document.prefs.group.value=''; document.prefs.submit();" />
-<?php endif; ?>
- </p>
-</div>
-</form>
diff --git a/horde/templates/prefs/enum.html b/horde/templates/prefs/enum.html
new file mode 100644 (file)
index 0000000..a0351da
--- /dev/null
@@ -0,0 +1,12 @@
+<div>
+ <tag:desc />
+ <tag:helplink />
+</div>
+
+<div>
+ <select id="<tag:pref />" name="<tag:pref />">
+<loop:enum>
+  <option<if:enum.s> selected="selected"</if:enum.s> value="<tag:enum.v />"><tag:enum.l /></option>
+</loop:enum>
+ </select>
+</div>
diff --git a/horde/templates/prefs/enum.inc b/horde/templates/prefs/enum.inc
deleted file mode 100644 (file)
index e6c253a..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-    $esc = !empty($_prefs[$pref]['escaped']);
-    $curval = $prefs->getValue($pref);
-?>
-<div>
- <?php echo Horde::label(htmlspecialchars($pref), $_prefs[$pref]['desc']) ?>
- <?php echo $helplink ?>
-</div>
-<div>
- <select id="<?php echo htmlspecialchars($pref) ?>" name="<?php echo htmlspecialchars($pref) ?>">
-<?php foreach ($_prefs[$pref]['enum'] as $key => $val): ?>
-  <option<?php echo ($curval == $key) ? ' selected="selected"' : '' ?> value="<?php echo $esc ? $key : htmlspecialchars($key) ?>"><?php echo $esc ? $val : htmlspecialchars($val) ?></option>
-<?php endforeach ?>
- </select>
-</div>
diff --git a/horde/templates/prefs/identityselect.html b/horde/templates/prefs/identityselect.html
new file mode 100644 (file)
index 0000000..f6495d7
--- /dev/null
@@ -0,0 +1,22 @@
+<if:locked>
+<input type="hidden" name="identity" value="<tag:default_identity />" />
+<else:locked>
+<div>
+ <tag:label />
+</div>
+<div>
+ <select name="identity" id="identity">
+  <option value="-2" selected="selected"><gettext>None</gettext></option>
+  <option value="-1"><gettext>Create New Identity</gettext></option>
+<loop:entry>
+  <option value="<tag:entry.i />"<if:entry.sel> selected="selected"</if:entry.sel>><tag:entry.label /></option>
+</loop:entry>
+ </select>
+</div>
+
+<div>
+ <p>
+  <input id="deleteidentity" type="button" class="button" value="<gettext>Delete</gettext>" />
+ </p>
+</div>
+</else:locked></if:locked>
diff --git a/horde/templates/prefs/identityselect.inc b/horde/templates/prefs/identityselect.inc
deleted file mode 100644 (file)
index b4606e4..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php if ($prefs->isLocked('default_identity')): ?>
-<input type="hidden" name="identity" value="<?php echo intval($GLOBALS['identity']->getDefault()) ?>" />
-<?php else: ?>
-<?php
-    $identities = $GLOBALS['identity']->getAll('id');
-    $default_identity = $GLOBALS['identity']->getDefault();
-    $members = $prefGroups['identities']['members'];
-
-    $out = array();
-
-    for ($i = 0, $icnt = count($identities); $i < $icnt; ++$i) {
-        $tmp = array();
-        foreach ($members as $member) {
-            if ($member == 'default_identity' ||
-                !empty($_prefs[$member]['locked']) ||
-                $_prefs[$member]['type'] == 'special' ||
-                $_prefs[$member]['type'] == 'link') {
-                continue;
-            }
-
-            $val = $GLOBALS['identity']->getValue($member, $i);
-            switch ($_prefs[$member]['type']) {
-            case 'checkbox':
-                $val2 = $val ? 'true' : 'false';
-                break;
-
-            case 'number':
-                $val2 = intval($val);
-                break;
-
-            case 'textarea':
-                if (is_array($val)) {
-                    $val = implode("\n", $val);
-                }
-                // Fall-through
-
-            default:
-                $val2 = Horde_String::convertCharset($val, Horde_Nls::getCharset(), 'UTF-8');
-            }
-
-            $tmp[] = array(
-                $member,
-                $_prefs[$member]['type'],
-                $val2
-            );
-        }
-
-        $out[] = $tmp;
-    }
-
-    Horde::addScriptFile('identityselect.js', 'horde');
-    echo Horde::wrapInlineScript(array(
-        'IdentitySelect.identities = ' . Horde_Serialize::serialize($out, Horde_Serialize::JSON)
-    ));
-?>
-<div>
- <?php echo Horde::label('identity', _("Select the identity you want to change:")) ?>
-</div>
-<div>
- <select name="identity" id="identity">
-  <option value="-2" selected="selected"><?php echo _("None") ?></option>
-  <option value="-1"><?php echo _("Create a new one") ?></option>
-<?php for ($i = 0, $icnt = count($identities); $i < $icnt; ++$i): ?>
-  <option value="<?php echo $i ?>"<?php if ($i == $default_identity) echo ' selected="selected"' ?>><?php echo htmlspecialchars($identities[$i]) ?></option>
-<?php endfor; ?>
- </select>
-</div>
-<?php endif; ?>
diff --git a/horde/templates/prefs/link.html b/horde/templates/prefs/link.html
new file mode 100644 (file)
index 0000000..2a7d789
--- /dev/null
@@ -0,0 +1,7 @@
+<div>
+<if:img>
+ <tag:img />
+</if:img>
+ <a href="<tag:url />"<if:target> target="<tag:target />"</if:target>><strong><tag:desc /></strong></a>
+ <tag:helplink />
+</div>
diff --git a/horde/templates/prefs/link.inc b/horde/templates/prefs/link.inc
deleted file mode 100644 (file)
index 918c02f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<div>
- <a href="<?php echo isset($_prefs[$pref]['url']) ? Horde::applicationUrl($_prefs[$pref]['url']) : $_prefs[$pref]['xurl'] ?>"<?php echo !empty($_prefs[$pref]['target']) ? ' target="' . htmlspecialchars($_prefs[$pref]['target']) . '"' : '' ?>>
- <?php if (isset($_prefs[$pref]['img'])) echo Horde::img($_prefs[$pref]['img'], $_prefs[$pref]['desc'], 'hspace="3"') ?><strong><?php echo $_prefs[$pref]['desc'] ?></strong></a>
- <?php echo $helplink ?>
-</div>
diff --git a/horde/templates/prefs/multienum.html b/horde/templates/prefs/multienum.html
new file mode 100644 (file)
index 0000000..546a83b
--- /dev/null
@@ -0,0 +1,12 @@
+<div>
+ <tag:desc />
+ <tag:helplink />
+</div>
+
+<div>
+ <select id="<tag:pref />" multiple="multiple" size="<tag:size />" name="<tag:pref />[]">
+<loop:enum>
+  <option<if:enum.s> selected="selected"</if:enum.s> value="<tag:enum.v />"><tag:enum.l /></option>
+</loop:enum>
+ </select>
+</div>
diff --git a/horde/templates/prefs/multienum.inc b/horde/templates/prefs/multienum.inc
deleted file mode 100644 (file)
index eb15473..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-    if (!$selected = @unserialize($prefs->getValue($pref))) {
-        $selected = array();
-    }
-
-    if (empty($_prefs[$pref]['enum'])) {
-        $_prefs[$pref]['enum'] = Horde_Util::nonInputVar($pref . '_options');
-    }
-?>
-<div>
- <?php echo Horde::label($pref, $_prefs[$pref]['desc']) ?>
- <?php echo $helplink ?>
-</div>
-<div>
- <select id="<?php echo $pref ?>" multiple="multiple" size="<?php echo min(4, count($_prefs[$pref]['enum'])) ?>" name="<?php echo $pref ?>[]">
-<?php foreach ($_prefs[$pref]['enum'] as $key => $val): ?>
-  <option<?php echo in_array($key, $selected) ? ' selected="selected" ' : '' ?> value="<?php echo htmlspecialchars($key) ?>"><?php echo htmlspecialchars($val) ?></option>
-<?php endforeach ?>
- </select>
-</div>
diff --git a/horde/templates/prefs/number.html b/horde/templates/prefs/number.html
new file mode 100644 (file)
index 0000000..4605987
--- /dev/null
@@ -0,0 +1,8 @@
+<div>
+ <tag:desc />
+ <tag:helplink />
+</div>
+
+<div>
+ <input type="text" id="<tag:pref />" name="<tag:pref />" size="3" maxlength="3" value="<tag:val />" />
+</div>
diff --git a/horde/templates/prefs/number.inc b/horde/templates/prefs/number.inc
deleted file mode 100644 (file)
index 78b3882..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<div>
- <?php echo Horde::label($pref, $_prefs[$pref]['desc']) ?>
- <?php echo $helplink ?>
-</div>
-<div>
- <input type="text" id="<?php echo $pref ?>" name="<?php echo $pref ?>" size="3" maxlength="3" value="<?php echo htmlspecialchars($prefs->getValue($pref)) ?>" />
-</div>
diff --git a/horde/templates/prefs/overview.html b/horde/templates/prefs/overview.html
new file mode 100644 (file)
index 0000000..44a5bad
--- /dev/null
@@ -0,0 +1,19 @@
+<div class="prefsOverview">
+<loop:columns>
+ <div style="width:<tag:columns.width />%">
+  <div>
+   <h2><tag:columns.hdr /></h2>
+   <dl>
+<loop:columns.groups>
+    <dt>
+     <tag:columns.groups.link />
+    </dt>
+    <dd>
+     <tag:columns.groups.desc />
+    </dd>
+</loop:columns.groups>
+   </dl>
+  </div>
+ </div>
+</loop:columns>
+</div>
diff --git a/horde/templates/prefs/overview.inc b/horde/templates/prefs/overview.inc
deleted file mode 100644 (file)
index df55906..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<div class="prefsOverview">
-<?php foreach ($columns as $key => $column): ?>
- <div style="width:<?php echo $span - 1 ?>%">
-  <div>
-   <h2><?php echo htmlspecialchars($key) ?></h2>
-   <dl>
-<?php foreach ($column as $group => $gvals): ?>
-<?php if (Horde_Prefs_Ui::groupIsEditable($group, $prefGroups)): ?>
-     <dt><?php echo Horde::widget(Horde_Util::addParameter(Horde::selfUrl(), array('app' => $GLOBALS['app'], 'group' => $group)), $gvals['label'], '', '', '', $gvals['label']) ?></dt>
-     <dd><?php echo htmlspecialchars($gvals['desc']) ?></dd>
-<?php endif; ?>
-<?php endforeach; ?>
-   </dl>
-  </div>
- </div>
-<?php endforeach; ?>
-</div>
diff --git a/horde/templates/prefs/password.html b/horde/templates/prefs/password.html
new file mode 100644 (file)
index 0000000..d133c47
--- /dev/null
@@ -0,0 +1,8 @@
+<div>
+ <tag:desc />
+ <tag:helplink />
+</div>
+
+<div>
+ <input type="password" id="<tag:pref />" name="<tag:pref />" size="30" maxlength="60" value="<tag:val />" />
+</div>
diff --git a/horde/templates/prefs/password.inc b/horde/templates/prefs/password.inc
deleted file mode 100644 (file)
index 1a2645d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<div>
- <?php echo Horde::label($pref, $_prefs[$pref]['desc']) ?>
- <?php echo $helplink ?>
-</div>
-<div>
- <input type="password" id="<?php echo $pref ?>" name="<?php echo $pref ?>" size="30" maxlength="60" value="<?php echo htmlspecialchars($prefs->getValue($pref)) ?>" />
-</div>
diff --git a/horde/templates/prefs/rawhtml.html b/horde/templates/prefs/rawhtml.html
new file mode 100644 (file)
index 0000000..6b3b0aa
--- /dev/null
@@ -0,0 +1,3 @@
+<div>
+ <tag:html />
+</div>
diff --git a/horde/templates/prefs/rpc.html b/horde/templates/prefs/rpc.html
new file mode 100644 (file)
index 0000000..b3788ee
--- /dev/null
@@ -0,0 +1,38 @@
+<div>
+ <tag:serverlabel />
+ <select id="server" name="server">
+  <option value="-1"><gettext>Select a server</gettext>:</option>
+<loop:serverlist>
+  <option value="<tag:serverlist.i />"><tag:serverlist.l /></option>
+</loop:serverlist>
+ </select>
+</div>
+
+<div>
+ <tag:urllabel />
+</div>
+<div>
+ <input type="text" id="url" name="url" size="30" maxlength="60" />
+</div>
+
+<div>
+ <tag:userlabel />
+</div>
+<div>
+ <input type="text" id="user" name="user" size="30" maxlength="60" />
+</div>
+
+<div>
+ <tag:passwdlabel />
+</div>
+<div>
+ <input type="password" id="passwd" name="passwd" size="30" maxlength="60" />
+</div>
+
+<p class="nowrap">
+ <input type="submit" id="rpc_change" name="rpc_change" class="button" value="<gettext>Change</gettext>" />
+ <input type="submit" id="rpc_create" name="rpc_create" class="button" value="<gettext>Create</gettext>" />
+ <input type="submit" id="rpc_delete" name="rpc_delete" class="button" value="<gettext>Delete</gettext>" />
+ <input type="button" id="rpc_reset" class="button" value="<gettext>Reset</gettext>" />
+</p>
+
diff --git a/horde/templates/prefs/select.inc b/horde/templates/prefs/select.inc
deleted file mode 100644 (file)
index 5bc90af..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-    $esc = !empty($_prefs[$pref]['escaped']);
-    $curval = $prefs->getValue($pref);
-?>
-<div>
- <?php echo Horde::label(htmlspecialchars($pref), $_prefs[$pref]['desc']) ?>
- <?php echo $helplink ?>
-</div>
-<div>
- <select id="<?php echo htmlspecialchars($pref) ?>" name="<?php echo htmlspecialchars($pref) ?>">
-<?php foreach (Horde_Util::nonInputVar($pref . '_options') as $select_key => $select_val): ?>
-  <option value="<?php echo $esc ? $select_key : htmlspecialchars($select_key) ?>"<?php if ($select_key == $curval) echo ' selected="selected"' ?>><?php echo $esc ? $select_val : htmlspecialchars($select_val) ?></option>
-<?php endforeach; ?>
- </select>
-</div>
diff --git a/horde/templates/prefs/source.html b/horde/templates/prefs/source.html
new file mode 100644 (file)
index 0000000..cfa1dbc
--- /dev/null
@@ -0,0 +1,39 @@
+<input type="hidden" name="sources" id="sources" value="" />
+<div>
+ <p>
+  <tag:mainlabel />
+ </p>
+
+ <table>
+  <tr>
+   <td>
+    <label for="unselected_sources" class="hidden"><tag:unselectlabel /></label>
+    <select id="unselected_sources" name="unselected_sources" multiple="multiple" size="5">
+     <option class="control" disabled="disabled" value=""><tag:unselectlabel /></option>
+<loop:unselected>
+     <option value="<tag:unselected.v />"><tag:unselected.l /></option>
+</loop:unselected>
+    </select>
+   </td>
+   <td>
+    <a href="#" id="addsource"><tag:addimg /></a>
+    <br />
+    <a href="#" id="removesource"><tag:removeimg /></a>
+   </td>
+   <td>
+    <label for="selected_sources" class="hidden"><tag:selectlabel /></label>
+    <select name="selected_sources" multiple="multiple" size="5" id="selected_sources">
+     <option class="control" disabled="disabled" value=""><tag:selectlabel /></option>
+<loop:selected>
+     <option value="<tag:selected.v />"><tag:selected.l /></option>
+</loop:selected>
+    </select>
+   </td>
+   <td>
+    <a href="#" id="moveup"><tag:upimg /></a>
+    <br />
+    <a href="#" id="movedown"><tag:downimg /></a>
+   </td>
+  </tr>
+ </table>
+</div>
diff --git a/horde/templates/prefs/syncml.html b/horde/templates/prefs/syncml.html
new file mode 100644 (file)
index 0000000..474d231
--- /dev/null
@@ -0,0 +1,34 @@
+<div class="smallheader">
+ <gettext>Timestamps of successful synchronization sessions</gettext>
+</div>
+
+<if:devices>
+<table class="striped">
+ <tr>
+     <th><gettext>Device</gettext></th>
+     <th><gettext>Database</gettext></th>
+     <th><gettext>Server Time</gettext></th>
+     <th><gettext>Client Anchor</gettext></th>
+     <th><gettext>Delete</gettext></th>
+ </tr>
+<loop:devices>
+ <tr>
+  <td><tag:devices.device /></td>
+  <td><tag:devices.db /></td>
+  <td><tag:devices.time /></td>
+  <td><tag:devices.anchor /></td>
+  <td>
+   <a class="button" href="<tag:delete />"><gettext>Delete</gettext></a>
+  </td>
+ </tr>
+</loop:devices>
+</table>
+
+<p>
+ <input type="submit" class="button" name="deleteall" value="<gettext>Delete All SyncML Data</gettext>" />
+</p>
+<else:devices>
+<p>
+ <em><gettext>None</gettext></em>
+</p>
+</else:devices></if:devices>
diff --git a/horde/templates/prefs/text.html b/horde/templates/prefs/text.html
new file mode 100644 (file)
index 0000000..7670115
--- /dev/null
@@ -0,0 +1,8 @@
+<div>
+ <tag:desc />
+ <tag:helplink />
+</div>
+
+<div>
+ <input id="<tag:pref />" name="<tag:pref />" size="30" maxlength="60" value="<tag:val />" />
+</div>
diff --git a/horde/templates/prefs/text.inc b/horde/templates/prefs/text.inc
deleted file mode 100644 (file)
index a0d99ab..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<div>
- <?php echo Horde::label($pref, $_prefs[$pref]['desc']) ?>
- <?php echo $helplink ?>
-</div>
-<div>
- <input id="<?php echo $pref ?>" name="<?php echo $pref ?>" size="30" maxlength="60" value="<?php echo htmlspecialchars($prefs->getValue($pref)) ?>" />
-</div>
diff --git a/horde/templates/prefs/textarea.html b/horde/templates/prefs/textarea.html
new file mode 100644 (file)
index 0000000..8310931
--- /dev/null
@@ -0,0 +1,8 @@
+<div>
+ <tag:desc />
+ <tag:helplink />
+</div>
+
+<div class="fixed">
+ <textarea id="<tag:pref />" name="<tag:pref />" rows="4" cols="80" class="fixed"><tag:val /></textarea>
+</div>
diff --git a/horde/templates/prefs/textarea.inc b/horde/templates/prefs/textarea.inc
deleted file mode 100644 (file)
index 84a28df..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<div>
- <?php echo Horde::label($pref, $_prefs[$pref]['desc']) ?> <?php echo $helplink ?>
-</div>
-<div class="fixed">
- <textarea id="<?php echo $pref ?>" name="<?php echo $pref ?>" rows="4" cols="80" class="fixed"><?php echo htmlspecialchars($prefs->getValue($pref)) ?></textarea>
-</div>
diff --git a/horde/templates/rpcsum/rpcsum.inc b/horde/templates/rpcsum/rpcsum.inc
deleted file mode 100644 (file)
index e1cf580..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<script type="text/javascript">
-
-var cancelSubmit = false;
-
-var fields = [
-<?php for ($i = 0; $i < count($rpc_servers); $i++): ?>
-    [
-        "<?php echo rawurlencode($rpc_servers[$i]['url']) ?>",
-        "<?php echo rawurlencode($rpc_servers[$i]['user']) ?>"
-    ]<?php if ($i + 1 < count($rpc_servers)) echo ','; ?>
-
-<?php endfor; ?>
-];
-
-function newChoice()
-{
-    var action = document.prefs.server.options[document.prefs.server.selectedIndex].value;
-
-    if (action == -1) {
-        document.prefs.save.value = '<?php echo addslashes(_("Create")) ?>';
-        document.prefs.reset();
-    } else {
-        document.prefs.save.value = '<?php echo addslashes(_("Change")) ?>';
-        updateForm(action);
-    }
-}
-
-function updateForm(server)
-{
-    document.prefs.edit_server.value = server;
-    document.prefs.url.value = decodeURIComponent(fields[server][0]);
-    document.prefs.user.value = decodeURIComponent(fields[server][1]);
-}
-
-function clearForm()
-{
-    document.prefs.edit_server.value = '';
-    document.prefs.url.value =  fields[server][0];
-    document.prefs.user.value = fields[server][1];
-    document.prefs.server.selectedIndex = 0;
-    cancelSubmit = true;
-}
-
-function checkSubmit()
-{
-    cancel = cancelSubmit;
-    cancelSubmit = false;
-<?php if ($browser->getBrowser() == 'msie' && $browser->getMajor() >= 4): ?>
-    window.event.returnValue = !cancel;
-<?php endif; ?>
-    return !cancel;
-}
-
-</script>
-
-<p>
-<?php echo Horde::label('server', _("Your remote servers:")) ?><br />
-<select id="server" name="server" onchange="javascript:newChoice()">
-  <option value="-1"><?php echo _("Select a server") ?></option>
-<?php for ($i = 0; $i < count($rpc_servers); ++$i): ?>
-  <option value="<?php echo $i ?>"><?php echo htmlspecialchars($rpc_servers[$i]['url']) ?></option>
-<?php endfor; ?>
-</select>
-</p>
-
-<noscript>
- <br />
- <input type="submit" name="edit" class="button" value="<?php echo _("Edit") ?>" />
- <input type="submit" name="delete" class="button" value="<?php echo _("Delete") ?>" />
- <br />
-</noscript>
-
-<input type="hidden" name="edit_server" value="" />
-
-<p><?php echo Horde::label('url', _("Remote URL (http://www.example.com/horde):")) ?><br />
- <input type="text" id="url" name="url" size="30" maxlength="60" /></p>
-
-<p><?php echo Horde::label('user', _("Username:")) ?><br />
- <input type="text" id="user" name="user" size="30" maxlength="60" /></p>
-
-<p><?php echo Horde::label('passwd', _("Password:")) ?><br />
- <input type="password" id="passwd" name="passwd" size="30" maxlength="60" /></p>
-
-</div>
-
-<p class="nowrap">
- <input type="submit" name="save" class="button" onclick="document.prefs.actionID.value='save'; return true" value="<?php echo $actionID == 'edit' ? _("Change") : _("Create") ?>" />
-<script type="text/javascript">
-document.write('<input type="submit" name="delete" class="button" onclick="document.prefs.actionID.value=\'delete\'" value="<?php echo _("Delete") ?>" />');
-</script>
- <input type="submit" name="new" class="button" onclick="clearForm();document.prefs.save.value='<?php echo _("Create") ?>';" value="<?php echo _("Reset") ?>" />
- <input id="prefs_return" type="button" class="button" onclick="cancelSubmit=true;document.location.href='<?php echo Horde::applicationUrl(Horde_Util::addParameter('services/prefs.php', 'app', 'horde'), true) ?>'" value="<?php echo _("Return to Options") ?>" />
-</p>
-
-</form>
diff --git a/horde/templates/syncml/syncml.inc b/horde/templates/syncml/syncml.inc
deleted file mode 100644 (file)
index 33822b3..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<div class="smallheader">
- <?php echo _("Timestamps of successful synchronization sessions") ?>
-</div>
-<?php if (!$devices): ?>
-<em><?php echo _("None") ?></em>
-<?php else: ?>
-<table class="striped">
-<tr>
- <th><?php echo _("Device") ?></th>
- <th><?php echo _("Database") ?></th>
- <th><?php echo _("Server Time") ?></th>
- <th><?php echo _("Client Anchor") ?></th>
- <th><?php echo _("Delete") ?></th>
-</tr>
-<?php
-foreach ($devices as $device => $anchors) {
-    foreach ($anchors as $anchor) {
-?>
-<tr>
- <td><?php echo htmlspecialchars($device) ?></td>
- <td><?php echo htmlspecialchars($anchor['syncml_db']) ?></td>
- <td><?php echo strftime($prefs->getValue('date_format') . ' %H:%M', $anchor['syncml_serveranchor']) ?></td>
- <td><?php echo htmlspecialchars($anchor['syncml_clientanchor']) ?></td>
- <td>
-  <form method="post">
-   <input type="hidden" name="deviceid" value="<?php echo htmlspecialchars($device) ?>"/>
-   <input type="hidden" name="actionID" value="deleteanchor" />
-   <input type="hidden" name="db" value="<?php echo htmlspecialchars($anchor['syncml_db']) ?>" />
-   <input type="submit" class="button" value="<?php echo _("Delete") ?>" />
-  </form>
- </td>
-</tr>
-<?php } } ?>
-</table>
-<?php endif; ?>
-<p>
- <input type="hidden" name="actionID" value="deleteall" />
- <input type="submit" class="button" value="<?php echo _("Delete All SyncML Data") ?>" />
- <input id="prefs_return" type="button" class="button" onclick="cancelSubmit=true;document.location.href='<?php echo Horde::applicationUrl(Horde_Util::addParameter('services/prefs.php', 'app', 'horde'), true) ?>'" value="<?php echo _("Return to Options") ?>" />
-</p>
-
-</div>
-</form>
index b18bd2e..3b7ac81 100644 (file)
@@ -524,6 +524,9 @@ div.nicetitle {
     list-style: none;
     display: inline;
 }
+#services_prefs #app {
+    font-weight: bold;
+}
 .prefsOverview div {
     float: left;
 }
@@ -558,6 +561,9 @@ div.prefsContainer {
 div.prefsContainer p {
     padding-top: 1em;
 }
+img.prefsLinkImg {
+    padding-right: 1px;
+}
 
 /* Block styles. */
 .currentBlock {
diff --git a/imp/acl.php b/imp/acl.php
deleted file mode 100644 (file)
index 5588927..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-<?php
-/**
- * ACL (Access Control List) administration page.
- *
- * Copyright 2000-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author  Chris Hastie <imp@oak-wood.co.uk>
- * @author  Eric Garrido <ekg2002@columbia.edu>
- * @package IMP
- */
-
-require_once dirname(__FILE__) . '/lib/Application.php';
-Horde_Registry::appInit('imp');
-
-/* Redirect back to the options screen if ACL is not enabled. */
-$prefs_url = Horde::getServiceLink('options', 'imp');
-if ($prefs->isLocked('acl') || empty($_SESSION['imp']['imap']['acl'])) {
-    $notification->push('Folder sharing is not enabled.', 'horde.error');
-    header('Location: ' . $prefs_url);
-    exit;
-}
-
-try {
-    $ACL = $injector->getInstance('IMP_Imap_Acl');
-} catch (Horde_Exception $e) {
-    $notification->push(_("This server does not support sharing folders."), 'horde.error');
-    header('Location: ' . $prefs_url);
-    exit;
-}
-
-$vars = Horde_Variables::getDefaultVariables();
-
-/* Check to see if $vars->new_user already has an acl on the folder. */
-if ($vars->new_user && isset($vars->acl[$vars->new_user])) {
-    $vars->acl[$vars->new_user] = $vars->new_acl;
-    $vars->new_user = '';
-}
-
-$protected = $ACL->getProtected();
-
-/* Run through the action handlers. */
-switch ($vars->actionID) {
-case 'imp_acl_set':
-    if (!$vars->folder) {
-        $notification->push(_("No folder selected."), 'horde.error');
-        break;
-    }
-
-    if ($vars->new_user) {
-        try {
-            $ACL->editACL($vars->folder, $vars->new_user, $vars->new_acl);
-            if (count($vars->new_acl)) {
-                $notification->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $vars->new_user, $vars->folder), 'horde.success');
-            } else {
-                $notification->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), $vars->folder, $vars->new_user), 'horde.success');
-            }
-        } catch (Horde_Exception $e) {
-            $notification->push($e);
-        }
-    }
-
-    $curr_acl = $ACL->getACL($vars->folder);
-    foreach ($vars->acl as $user => $acl) {
-        if ($acl) {
-            $acl = array_flip($acl);
-            /* We had to have an empty value submitted to make sure all
-               users with acls were sent back, so we can remove those
-               without checkmarks. */
-            unset($acl['']);
-        } else {
-            $acl = array();
-        }
-
-        if (!$user) {
-            $notification->push(_("No user specified."), 'horde.error');
-            continue;
-        }
-
-        if (in_array($user, $protected)) {
-            if ($acl) {
-                $notification->push(sprintf(_("Rights for user \"%s\" cannot be modified."), $user), 'horde.error');
-            }
-            continue;
-        }
-
-        /* Check to see if ACL didn't change */
-        if ((isset($curr_acl[$user])) &&
-            (array_keys($curr_acl[$user]) == array_keys($acl))) {
-            continue;
-        }
-
-        try {
-            unset($curr_acl);
-            $ACL->editACL($vars->folder, $user, $acl);
-            if (!count($acl)) {
-                $notification->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), $vars->folder, $user), 'horde.success');
-            } else {
-                $notification->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $user, $vars->folder), 'horde.success');
-            }
-        } catch (Horde_Exception $e) {
-            $notification->push($e);
-        }
-    }
-    break;
-}
-
-$imp_folder = $injector->getInstance('IMP_Folder');
-$rights = $ACL->getRights();
-
-if (empty($vars->folder)) {
-    $vars->folder = 'INBOX';
-}
-
-if (!isset($curr_acl)) {
-    $curr_acl = $ACL->getACL($vars->folder);
-}
-$canEdit = $ACL->canEdit($vars->folder, Horde_Auth::getAuth());
-
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_Ui::generateHeader('imp', null, null, $chunk);
-
-/* Set up template. */
-$t = $injector->createInstance('Horde_Template');
-$t->setOption('gettext', true);
-$t->set('aclurl', Horde::applicationUrl('acl.php'));
-$t->set('forminput', Horde_Util::formInput());
-$t->set('aclnavcell', Horde_Util::bufferOutput(array('Horde_Prefs_Ui', 'generateNavigationCell'), 'imp', 'acl'));
-$t->set('changefolder', Horde::link('#', _("Change Folder"), 'smallheader', '', '', '', '', array('id' => 'changefolder')));
-$t->set('options', IMP::flistSelect(array('selected' => $vars->folder)));
-$t->set('current', sprintf(_("Current access to %s"), IMP::displayFolder($vars->folder)));
-$t->set('folder', $vars->folder);
-$t->set('noacl', !count($curr_acl));
-$t->set('maxrule', 1);
-if (!$t->get('noacl')) {
-    $i = 0;
-    $cval = array();
-    foreach ($curr_acl as $index => $rule) {
-        $entry = array(
-            'i' => ++$i,
-            'num_val' => ($i - 1),
-            'disabled' => in_array($index, $protected) || !$canEdit,
-            'index' => $index
-        );
-        /* Create table of each ACL option for each user granted permissions,
-         * enabled indicates the right has been given to the user */
-        foreach (array_keys($rights) as $val) {
-            $entry['rule'][] = array('val' => $val, 'enabled' => in_array($val, $rule));
-        }
-        $cval[] = $entry;
-    }
-    $t->set('curr_acl', $cval);
-    $t->set('maxval', count($curr_acl));
-    /* number of individual ACL options, for table rendering */
-    $t->set('maxrule', count($rights));
-}
-$t->set('canedit', $canEdit);
-if (empty($_SESSION['imp']['admin'])) {
-    $new_user_field = '<input id="new_user" type="text" name="new_user"/>';
-} else {
-    $current_users = array_keys($curr_acl);
-    $new_user_field = '<select id="new_user" name="new_user">';
-    foreach ($registry->callByPackage('userList', 'imp') as $user) {
-        if (in_array($user, $current_users)) {
-            continue;
-        }
-        $new_user_field .= "\n<option>" . htmlspecialchars($user) . '</option>';
-    }
-    $new_user_field .= "\n</select>";
-}
-$t->set('new_user', $new_user_field);
-
-$rightsTitlesval = array();
-foreach ($rights as $right => $val) {
-    $rightsval[] = array(
-        'right' => $right,
-        'desc' => $val['desc'],
-        'title' => $val['title']
-    );
-}
-
-$t->set('rights', $rightsval);
-$t->set('width', round(100 / (count($rightsval) + 1)) . '%');
-$t->set('prefsurl', $prefs_url);
-
-Horde::addScriptFile('acl.js', 'imp');
-echo $t->fetch(IMP_TEMPLATES . '/imp/acl/acl.html');
-if (!$chunk) {
-    require $registry->get('templates', 'horde') . '/common-footer.inc';
-}
index 5da230d..6291b41 100644 (file)
  * $Id$
  */
 
-// Make sure that constants are defined.
-$is_pop3 = isset($_SESSION['imp']['protocol']) && ($_SESSION['imp']['protocol'] == 'pop');
+// *** Personal Information Preferences ***
 
 $prefGroups['identities'] = array(
     'column' => _("General Options"),
     'label' => _("Personal Information"),
     'desc' => _("Change the name, address, and signature that people see when they read and reply to your email."),
-    'members' => array('replyto_addr', 'alias_addr', 'tieto_addr', 'bcc_addr',
-                       'signature', 'sig_dashes', 'sig_first',
-                       'save_sent_mail', 'sent_mail_folder', 'sentmailselect')
-);
-
-if (!$is_pop3) {
-    $prefGroups['server'] = array(
-        'column' => _("General Options"),
-        'label' => _("Server and Folder Information"),
-        'desc' => _("Change mail server and folder settings."),
-        'members' => array('use_vinbox', 'subscribe', 'draftsselect',
-                           'trashselect', 'spamselect')
-        );
-}
-
-if (!empty($_SESSION['imp']['imap']['acl'])) {
-    $prefGroups['acl'] = array(
-        'column' => _("General Options"),
-        'label' => _("Share Folders"),
-        'desc' => _("Share your mail folders with other users."),
-        'url' => 'acl.php'
-    );
-}
-
-$prefGroups['logintasks'] = array(
-    'column' => _("General Options"),
-    'label' => _("Login Tasks"),
-    'desc' => sprintf(_("Configure tasks to run upon logon to %s."), $GLOBALS['registry']->get('name')),
-    'members' => array('delete_attachments_monthly',
-                       'delete_attachments_monthly_keep')
-);
-if (!$is_pop3) {
-    $prefGroups['logintasks']['members'] = array_merge(
-        $prefGroups['logintasks']['members'],
-        array('initialpageselect', 'rename_sentmail_monthly',
-              'delete_sentmail_monthly', 'delete_sentmail_monthly_keep',
-              'purge_sentmail', 'purge_sentmail_interval',
-              'purge_sentmail_keep', 'purge_trash', 'purge_trash_interval',
-              'purge_trash_keep', 'purge_spam', 'purge_spam_interval',
-              'purge_spam_keep'));
-}
-
-if (!empty($GLOBALS['conf']['user']['allow_accounts'])) {
-    $prefGroups['accounts'] = array(
-        'column' => _("General Options"),
-        'label' => _("Additional Accounts"),
-        'desc' => _("Configure additional mail accounts to display."),
-        'members' => array('accountsmanagement')
-    );
-}
-
-$prefGroups['compose'] = array(
-    'column' => _("Message Options"),
-    'label' => _("Message Composition"),
-    'desc' => _("Configure how you send mail."),
-    'members' => array('stationery_link', 'mailto_handler', 'compose_cc',
-                       'compose_bcc', 'compose_spellcheck', 'compose_confirm',
-                       'set_priority', 'compose_popup', 'compose_html',
-                       'ckeditor_buttons', 'mail_domain',
-                       'compose_cursor', 'sending_charset', 'encryptselect',
-                       'save_attachments')
-);
-
-if (!empty($GLOBALS['conf']['compose']['allow_receipts'])) {
-    $prefGroups['compose']['members'] = array_merge($prefGroups['compose']['members'], array('disposition_request_read'));
-}
-
-$prefGroups['reply'] = array(
-    'column' => _("Message Options"),
-    'label' => _("Message Replies"),
-    'desc' => _("Configure how you reply to mail."),
-    'members' => array('reply_quote', 'reply_format', 'reply_headers',
-                       'attrib_text')
-);
-
-$prefGroups['forward'] = array(
-    'column' => _("Message Options"),
-    'label' => _("Message Forwards"),
-    'desc' => _("Configure how you forward mail."),
-    'members' => array('forward_default', 'forward_format')
+    'members' => array(
+        'replyto_addr', 'alias_addr', 'tieto_addr', 'bcc_addr', 'signature',
+        'sig_dashes', 'sig_first', 'save_sent_mail', 'sent_mail_folder',
+        'sentmailselect'
+    )
 );
 
-$prefGroups['drafts'] = array(
-    'column' => _("Message Options"),
-    'label' => _("Message Drafts"),
-    'desc' => _("Configure how to deal with message drafts."),
-    'members' => array('draftsselect', 'close_draft', 'unseen_drafts',
-                       'auto_save_drafts', 'auto_delete_drafts')
-);
-
-$prefGroups['viewing'] = array(
-    'column' => _("Message Options"),
-    'label' => _("Message Viewing"),
-    'desc' => _("Configure how messages are displayed."),
-    'members' => array('filtering', 'strip_attachments',
-                       'html_image_replacement', 'html_image_addrbook',
-                       'highlight_text', 'highlight_simple_markup',
-                       'show_quoteblocks', 'dim_signature', 'emoticons',
-                       'parts_display', 'mail_hdr', 'default_msg_charset')
-);
-if (!empty($GLOBALS['conf']['maillog']['use_maillog'])) {
-    $prefGroups['viewing']['members'] = array_merge($prefGroups['viewing']['members'], array('disposition_send_mdn'));
-}
-
-$prefGroups['delmove'] = array(
-    'column' => _("Message Options"),
-    'label' => _("Deleting and Moving Messages"),
-    'desc' => _("Set preferences for what happens when you move and delete messages."),
-    'members' => array('mailbox_return', 'delete_spam_after_report',
-                       'move_ham_after_report', 'empty_spam_menu')
-);
-if (!$is_pop3) {
-    $prefGroups['delmove']['members'] = array_merge(
-        $prefGroups['delmove']['members'],
-        array('use_trash', 'trashselect', 'use_vtrash', 'empty_trash_menu'));
-}
-
-$prefGroups['newmail'] = array(
-    'column' => _("Message Options"),
-    'label' => _("New Mail"),
-    'desc' => _("Control when new mail will be checked for, and whether or not to notify you when it arrives."),
-    'members' => array('refresh_time', 'nav_poll_all', 'nav_popup', 'soundselect')
-);
-
-if (!$is_pop3) {
-    $prefGroups['flags'] = array(
-        'column' => _("Message Options"),
-        'label' => _("Message Flags"),
-        'desc' => _("Configure flag highlighting."),
-        'members' => array('flagmanagement')
-    );
-}
-
-$prefGroups['display'] = array(
-    'column' => _("Other Options"),
-    'label' => _("Mailbox and Folder Display Options"),
-    'desc' => _("Change display options such as how many messages you see on each page and how messages are sorted."),
-    'members' => array('mailbox_start', 'sortby', 'sortdir', 'max_msgs',
-                       'from_link', 'time_format', 'atc_flag')
-);
-if (!$is_pop3) {
-    $prefGroups['display']['members'] = array_merge(
-        $prefGroups['display']['members'],
-        array('nav_expanded', 'tree_view', 'nav_expanded_sidebar'));
-}
-
-$prefGroups['filters'] = array(
-    'column' => _("Other Options"),
-    'label' => _("Filters"),
-    'desc' => _("Create filtering rules to organize your incoming mail, sort it into folders, and delete spam."),
-    'url' => 'filterprefs.php'
-);
-
-$contacts_app = $GLOBALS['registry']->hasInterface('contacts');
-if ($contacts_app && $GLOBALS['registry']->hasPermission($contacts_app)) {
-    $prefGroups['addressbooks'] = array(
-        'column' => _("Other Options"),
-        'label' => _("Address Books"),
-        'desc' => _("Select address book sources for adding and searching for addresses."),
-        'members' => array('save_recipients', 'display_contact', 'sourceselect')
-        );
-}
-
-$prefGroups['events'] = array(
-    'column' => _("Other Options"),
-    'label' => _("Event Requests"),
-    'desc' => _("Configure how event or meeting requests should be handled."),
-    'members' => array('conflict_interval')
-);
-
-if (isset($GLOBALS['conf']['gnupg']['path'])) {
-    $prefGroups['pgp'] = array(
-        'column' => _("Other Options"),
-        'label' => _("PGP Options"),
-        'desc' => sprintf(_("Control PGP support for %s."), $GLOBALS['registry']->get('name')),
-        'url' => 'pgp.php'
-    );
-}
-
-if (Horde_Util::extensionExists('openssl') && isset($GLOBALS['conf']['openssl']['path'])) {
-    $prefGroups['smime'] = array(
-        'column' => _("Other Options"),
-        'label' => _("S/MIME Options"),
-        'desc' => sprintf(_("Control S/MIME support for %s."), $GLOBALS['registry']->get('name')),
-        'url' => 'smime.php'
-    );
-}
-
-$prefGroups['mimp'] = array(
-    'column' => _("Other Options"),
-    'label' => _("Mobile View Options"),
-    'desc' => _("Configure options for the mobile view."),
-    'members' => array('mimp_preview_msg', 'mimp_download_confirm',
-                       'mimp_inline_all')
-);
-
-$prefGroups['standard'] = array(
-    'column' => _("Other Options"),
-    'label' => _("Standard View Options"),
-    'desc' => _("Configure options for the standard view."),
-    'members' => array('preview_enabled', 'preview_maxlen', 'preview_strip_nl', 'preview_show_unread', 'preview_show_tooltip')
-);
-
-$prefGroups['dimp'] = array(
-    'column' => _("Other Options"),
-    'label' => _("Dynamic View Options"),
-    'desc' => _("Configure options for the dynamic view."),
-    'members' => array('dimp_login_view')
-);
-
-
-// Personal Information preferences
-
 // user preferred email address for Reply-To:, if different from From:
 $_prefs['replyto_addr'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'text',
-    'desc' => _("Your Reply-to: address: <em>(optional)</em>"));
+    'desc' => _("Your Reply-to: address: <em>(optional)</em>")
+);
 
 // user preferred alias addresses
 $_prefs['alias_addr'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'textarea',
-    'desc' => _("Your alias addresses: <em>(optional, enter each address on a new line)</em>"));
+    'desc' => _("Your alias addresses: <em>(optional, enter each address on a new line)</em>")
+);
 
 // user preferred 'tie to' addresses
 $_prefs['tieto_addr'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'textarea',
-    'desc' => _("Addresses to explicitly tie to this identity: <em>(optional, enter each address on a new line)</em>"));
+    'desc' => _("Addresses to explicitly tie to this identity: <em>(optional, enter each address on a new line)</em>")
+);
 
 // Automatically Bcc addresses when composing
 $_prefs['bcc_addr'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'textarea',
-    'desc' => _("Addresses to BCC all messages: <em>(optional, enter each address on a new line)</em>"));
+    'desc' => _("Addresses to BCC all messages: <em>(optional, enter each address on a new line)</em>")
+);
 
 // user signature
 $_prefs['signature'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'textarea',
-    'desc' => _("Your signature:"));
+    'desc' => _("Your signature:")
+);
 
 // precede the signature with dashes ('-- ')?
 $_prefs['sig_dashes'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Precede your signature with dashes ('-- ')?"));
+    'desc' => _("Precede your signature with dashes ('-- ')?")
+);
 
 // signature before replies and forwards?
 $_prefs['sig_first'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Place your signature before replies and forwards?"));
+    'desc' => _("Place your signature before replies and forwards?")
+);
 
 // save a copy of sent messages?
 $_prefs['save_sent_mail'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Save sent mail?"));
+    'desc' => _("Save sent mail?")
+);
 
 // sent mail folder
 $_prefs['sent_mail_folder'] = array(
@@ -300,39 +85,50 @@ $_prefs['sent_mail_folder'] = array(
     // necessary conversion.
     // 'value' => Horde_String::convertCharset('Sent', null, 'UTF7-IMAP'),
     // Exchange servers use this default value instead.
-    // 'value' => 'Sent Items',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    // 'value' => 'Sent Items'
+);
 
-// sent mail folder selection widget. includes some javascript, so it's
-// specific to IMP.
-$_prefs['sentmailselect'] = array('type' => 'special');
+// sent mail folder selection widget.
+$_prefs['sentmailselect'] = array(
+    'type' => 'special'
+);
 
-// End Personal Information preferences
 
 
-// Server and Folder Information preferences
+// *** Server and Folder Preferences ***
+
+$prefGroups['server'] = array(
+    'column' => _("General Options"),
+    'label' => _("Server and Folder Information"),
+    'desc' => _("Change mail server and folder settings."),
+    'members' => array(
+        'use_vinbox', 'subscribe', 'draftsselect', 'trashselect', 'spamselect'
+    )
+);
 
 // display Virtual INBOX?
 $_prefs['use_vinbox'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Display Virtual Inbox?"));
+    'desc' => _("Display Virtual Inbox?")
+);
+
+// virtual inbox identifier
+$_prefs['vinbox_id'] = array(
+    'value' => ''
+);
 
 // use IMAP subscribe?
 $_prefs['subscribe'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Use IMAP folder subscriptions?"));
+    'desc' => _("Use IMAP folder subscriptions?")
+);
 
-// drafts folder selection widget. includes some javascript, so it's specific
-// to IMP.
-$_prefs['draftsselect'] = array('type' => 'special');
+// drafts folder selection widget.
+$_prefs['draftsselect'] = array(
+    'type' => 'special'
+);
 
 // drafts folder
 $_prefs['drafts_folder'] = array(
@@ -343,14 +139,13 @@ $_prefs['drafts_folder'] = array(
     // If the mailbox value contains non-ASCII characters, it must be encoded
     // in the UTF7-IMAP charset (RFC 3501 [5.1.3]). This entry will do the
     // necessary conversion.
-    // 'value' => Horde_String::convertCharset('Drafts', null, 'UTF7-IMAP'),
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    // 'value' => Horde_String::convertCharset('Drafts', null, 'UTF7-IMAP')
+);
 
-// trash folder selection widget. includes some javascript, so it's
-// specific to IMP.
-$_prefs['trashselect'] = array('type' => 'special');
+// trash folder selection widget.
+$_prefs['trashselect'] = array(
+    'type' => 'special'
+);
 
 // trash folder
 $_prefs['trash_folder'] = array(
@@ -363,242 +158,258 @@ $_prefs['trash_folder'] = array(
     // necessary conversion.
     // 'value' => Horde_String::convertCharset('Trash', null, 'UTF7-IMAP'),
     // Exchange servers use this default value instead.
-    // 'value' => 'Deleted Items',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    // 'value' => 'Deleted Items'
+);
 
-// spam folder selection widget. includes some javascript, so it's
-// specific to IMP.
-$_prefs['spamselect'] = array('type' => 'special');
+// spam folder selection widget.
+$_prefs['spamselect'] = array(
+    'type' => 'special'
+);
 
 // spam folder
 $_prefs['spam_folder'] = array(
     // NOTE: Localization of this name for display purposes is done
     // automatically. This entry only needs to be changed if the mailbox name
     // on the IMAP server is different than this value.
-    'value' => 'Spam',
+    'value' => 'Spam'
     // If the mailbox value contains non-ASCII characters, it must be encoded
     // in the UTF7-IMAP charset (RFC 3501 [5.1.3]). This entry will do the
     // necessary conversion.
-    // 'value' => Horde_String::convertCharset('Spam', null, 'UTF7-IMAP'),
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    // 'value' => Horde_String::convertCharset('Spam', null, 'UTF7-IMAP')
+);
 
 $_prefs['vfolder'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ''
+);
+
+
 
-// End Server and Folder Information preferences
+// *** ACL Preferences ***
 
+$prefGroups['acl'] = array(
+    'column' => _("General Options"),
+    'label' => _("Share Folders"),
+    'desc' => _("Share your mail folders with other users."),
+    'members' => array('aclmanagement')
+);
 
-// Folder sharing preferences
+// ACL preference management screen
+$_prefs['aclmanagement'] = array(
+    'type' => 'special'
+);
 
 // folder sharing options
 $_prefs['acl'] = array(
-    'value' => '',
     // set 'locked' => true to disable folder sharing
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ''
+);
+
 
-// End folder sharing preferences
 
+// *** Login Tasks Preferences ***
+
+$prefGroups['logintasks'] = array(
+    'column' => _("General Options"),
+    'label' => _("Login Tasks"),
+    'desc' => sprintf(_("Configure tasks to run upon logon to %s."), $GLOBALS['registry']->get('name')),
+    'members' => array(
+        'delete_attachments_monthly', 'delete_attachments_monthly_keep',
+        'initialpageselect', 'rename_sentmail_monthly',
+        'delete_sentmail_monthly', 'delete_sentmail_monthly_keep',
+        'purge_sentmail', 'purge_sentmail_interval', 'purge_sentmail_keep',
+        'purge_trash', 'purge_trash_interval', 'purge_trash_keep',
+        'purge_spam', 'purge_spam_interval', 'purge_spam_keep'
+    )
+);
 
-// Login Tasks preferences
+// purge old attachments every month?
+$_prefs['delete_attachments_monthly'] = array(
+    'value' => 1,
+    'type' => 'checkbox',
+    'desc' => _("Delete old linked attachments at beginning of month?"),
+    'help' => 'prefs-delete_attachments_monthly'
+);
+
+// how many old months of attachments to keep?
+$_prefs['delete_attachments_monthly_keep'] = array(
+    'value' => 6,
+    'type' => 'number',
+    'desc' => _("Number of months to keep old linked attachments if deleting monthly."),
+    'help' => 'prefs-delete_attachments_monthly_keep'
+);
 
 // select widget for the initial_page preference
-$_prefs['initialpageselect'] = array('type' => 'special');
+$_prefs['initialpageselect'] = array(
+    'type' => 'special'
+);
 
 // the page to display. Either a filename like 'folders.php'
 // or a mailbox name.
 $_prefs['initial_page'] = array(
-    'value' => 'INBOX',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 'INBOX'
+);
 
 // rename sent-mail folder every month?
 $_prefs['rename_sentmail_monthly'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Rename sent-mail folder at beginning of month?"),
-    'help' => 'prefs-rename_sentmail_monthly');
+    'help' => 'prefs-rename_sentmail_monthly'
+);
 
 // delete sent-mail folders every month?
 $_prefs['delete_sentmail_monthly'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Delete old sent-mail folders at beginning of month?"),
-    'help' => 'prefs-delete_sentmail_monthly');
+    'help' => 'prefs-delete_sentmail_monthly'
+);
 
 // how many old sent-mail folders to keep every month?
 $_prefs['delete_sentmail_monthly_keep'] = array(
     'value' => 12,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Number of old sent-mail folders to keep if deleting monthly."),
-    'help' => 'prefs-delete_sentmail_monthly_keep');
+    'help' => 'prefs-delete_sentmail_monthly_keep'
+);
 
 // purge sent-mail folder?
 $_prefs['purge_sentmail'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Purge old messages in the sent-mail folder(s)?"),
-    'help' => 'prefs-purge_sentmail');
+    'help' => 'prefs-purge_sentmail'
+);
 
 // how often to purge the Sent-Mail folder?
 $_prefs['purge_sentmail_interval'] = array(
     'value' => Horde_LoginTasks::MONTHLY,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => Horde_LoginTasks::getLabels(),
     'desc' => _("Purge sent-mail how often:"),
-    'help' => 'prefs-purge_sentmail_interval');
+    'help' => 'prefs-purge_sentmail_interval'
+);
 
 // when purging sent-mail folder, purge messages older than how many days?
 $_prefs['purge_sentmail_keep'] = array(
     'value' => 30,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Purge messages in sent-mail folder(s) older than this amount of days."),
-    'help' => 'prefs-purge_sentmail_keep');
+    'help' => 'prefs-purge_sentmail_keep'
+);
 
-// purge old attachments every month?
-$_prefs['delete_attachments_monthly'] = array(
-    'value' => 1,
-    'locked' => false,
-    'shared' => false,
+// purge Trash folder?
+$_prefs['purge_trash'] = array(
+    'value' => 0,
     'type' => 'checkbox',
-    'desc' => _("Delete old linked attachments at beginning of month?"),
-    'help' => 'prefs-delete_attachments_monthly');
+    'desc' => _("Purge old messages in the Trash folder?"),
+    'help' => 'prefs-purge_trash'
+);
 
-// how many old months of attachments to keep?
-$_prefs['delete_attachments_monthly_keep'] = array(
-    'value' => 6,
-    'locked' => false,
-    'shared' => false,
+// how often to purge the Trash folder?
+$_prefs['purge_trash_interval'] = array(
+    'value' => Horde_LoginTasks::MONTHLY,
+    'type' => 'enum',
+    'enum' => Horde_LoginTasks::getLabels(),
+    'desc' => _("Purge Trash how often:"),
+    'help' => 'prefs-purge_trash_interval'
+);
+
+// when purging Trash folder, purge messages older than how many days?
+$_prefs['purge_trash_keep'] = array(
+    'value' => 30,
     'type' => 'number',
-    'desc' => _("Number of months to keep old linked attachments if deleting monthly."),
-    'help' => 'prefs-delete_attachments_monthly_keep');
+    'desc' => _("Purge messages in Trash folder older than this amount of days."),
+    'help' => 'prefs-purge_trash_keep'
+);
 
 // purge Spam folder?
 $_prefs['purge_spam'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Purge old messages in the Spam folder?"),
-    'help' => 'prefs-purge_spam');
+    'help' => 'prefs-purge_spam'
+);
 
 // how often to purge the Spam folder?
 $_prefs['purge_spam_interval'] = array(
     'value' => Horde_LoginTasks::MONTHLY,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => Horde_LoginTasks::getLabels(),
     'desc' => _("Purge Spam how often:"),
-    'help' => 'prefs-purge_spam_interval');
+    'help' => 'prefs-purge_spam_interval'
+);
 
 // when purging Spam folder, purge messages older than how many days?
 $_prefs['purge_spam_keep'] = array(
     'value' => 30,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Purge messages in Spam folder older than this amount of days."),
-    'help' => 'prefs-purge_spam_keep');
+    'help' => 'prefs-purge_spam_keep'
+);
 
-// purge Trash folder?
-$_prefs['purge_trash'] = array(
-    'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'checkbox',
-    'desc' => _("Purge old messages in the Trash folder?"),
-    'help' => 'prefs-purge_trash');
 
-// how often to purge the Trash folder?
-$_prefs['purge_trash_interval'] = array(
-    'value' => Horde_LoginTasks::MONTHLY,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'enum',
-    'enum' => Horde_LoginTasks::getLabels(),
-    'desc' => _("Purge Trash how often:"),
-    'help' => 'prefs-purge_trash_interval');
-
-// when purging Trash folder, purge messages older than how many days?
-$_prefs['purge_trash_keep'] = array(
-    'value' => 30,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'number',
-    'desc' => _("Purge messages in Trash folder older than this amount of days."),
-    'help' => 'prefs-purge_trash_keep');
-
-// End Login Tasks preferences
 
+// *** Additional Accounts Preferences ***
 
-// Accounts preferences
+$prefGroups['accounts'] = array(
+    'column' => _("General Options"),
+    'label' => _("Additional Accounts"),
+    'desc' => _("Configure additional mail accounts to display."),
+    'members' => array('accountsmanagement')
+);
 
 // UI for flag management.
 $_prefs['accountsmanagement'] = array(
     'type' => 'special'
 );
 
+// Internal accounts storage value
 $_prefs['accounts'] = array(
-    'value' => json_encode(array()),
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    // 'value' = json_encode(array())
+    'value' => '[]'
+);
 
-// End Accounts preferences
 
 
-// Message Composition preferences
+// *** Compose Preferences ***
+
+$prefGroups['compose'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Message Composition"),
+    'desc' => _("Configure how you send mail."),
+    'members' => array(
+        'stationery_link', 'mailto_handler', 'compose_cc', 'compose_bcc',
+        'compose_spellcheck', 'compose_confirm', 'set_priority',
+        'compose_popup', 'compose_html', 'mail_domain', 'compose_cursor',
+        'sending_charset', 'encryptselect', 'save_attachments',
+        'disposition_request_read'
+    )
+);
 
 // Link to the stationery preferences.
 $_prefs['stationery_link'] = array(
-    'type' => 'link',
-    'url' => 'stationery.php',
-    'desc' => _("To the stationery and form responses."));
-
-$_prefs['stationery'] = array(
-    // value = serialize(array())
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'prefslink',
+    'group' => 'stationery',
+    'img' => 'compose.png',
+    'desc' => _("Edit stationery and form responses.")
+);
 
 // Link to add a Firefox 3 mailto: handler
 $_prefs['mailto_handler'] = array(
     'type' => 'link',
+    'img' => 'compose.png',
     'xurl' => 'javascript:if(typeof navigator.registerProtocolHandler==\'undefined\')alert(\''
         . addslashes(_("Your browser does not support this feature."))
         . '\');else navigator.registerProtocolHandler(\'mailto\',\''
         . Horde::applicationUrl('compose.php', true)->setRaw(true)->add(array('actionID' => 'mailto_link', 'to' => ''))
         . '%s\',\'' . $GLOBALS['registry']->get('name') . '\');',
-    'desc' => sprintf(_("Click here to open all mailto: links in %s."), $GLOBALS['registry']->get('name')));
+    'desc' => sprintf(_("Click here to open all mailto: links in %s."), $GLOBALS['registry']->get('name'))
+);
 
 // Show Cc: field?
 $_prefs['compose_cc'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show the Cc: header field when composing mail?")
 );
@@ -606,8 +417,6 @@ $_prefs['compose_cc'] = array(
 // Show Bcc: field?
 $_prefs['compose_bcc'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show the Bcc: header field when composing mail?")
 );
@@ -615,33 +424,29 @@ $_prefs['compose_bcc'] = array(
 // Check spelling before sending the message?
 $_prefs['compose_spellcheck'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Check spelling before sending a message?"));
+    'desc' => _("Check spelling before sending a message?")
+);
 
 // confirm successful sending of messages?
 $_prefs['compose_confirm'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Display confirmation after sending a message?"));
+    'desc' => _("Display confirmation after sending a message?")
+);
 
 // allow the user to add a priority header when composing messages?
 $_prefs['set_priority'] = array(
     'value' => 1,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Set a priority header when composing messages?"));
+    'desc' => _("Set a priority header when composing messages?")
+);
 
 // compose in a separate window?
 $_prefs['compose_popup'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Compose messages in a separate window?")
 );
@@ -650,70 +455,51 @@ $_prefs['compose_popup'] = array(
 // default?
 $_prefs['compose_html'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Compose messages with an HTML editor by default?")
 );
 
-// The list of buttons to show in CKeditor
-// See http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Toolbar for
-// details on configuration
-$_prefs['ckeditor_buttons'] = array(
-    'value' => "[['Source','Maximize','-','Templates'],['Cut','Copy','Paste','PasteText','PasteFromWord'],['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],'/',['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],['Link','Unlink'],['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar'],'/',['Styles','Format','Font','FontSize'],['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],['TextColor','BGColor']]",
-    // Use the following line for a very basic set of buttons:
-    // 'value' => "['Bold','Italic','-','NumberedList','BulletedList','-','Link','Unlink']",
-    // Locked by default
-    'locked' => true,
-    'shared' => false,
-    'type' => 'textarea',
-    'desc' => _("The buttons to show when using the HTML editor.")
-);
-
 // default outgoing mail domain and address completion
 $_prefs['mail_domain'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'text',
-    'desc' => _("When sending mail or expanding addresses, what domain should we append to unqualified addresses (email addresses without \"@\")?"));
+    'desc' => _("When sending mail or expanding addresses, what domain should we append to unqualified addresses (email addresses without \"@\")?")
+);
 
 // Where should the cursor be located in the compose text area by default?
 $_prefs['compose_cursor'] = array(
     'value' => 'top',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('top' => _("Top"),
-                    'bottom' => _("Bottom"),
-                    'sig' => _("Before Signature")),
+    'enum' => array(
+        'top' => _("Top"),
+        'bottom' => _("Bottom"),
+        'sig' => _("Before Signature")
+    ),
     'desc' => _("Where should the cursor be located in the compose text area by default?")
 );
 
 // Select widget for the possible charsets
 $_prefs['sending_charset'] = array(
     'value' => '',
-    'locked' => false,
     'shared' => true,
     'type' => 'enum',
     'enum' => array_merge(array('' => _("Default")), Horde_Nls::$config['encodings']),
-    'desc' => _("Your default charset for sending messages:"));
+    'desc' => _("Your default charset for sending messages:")
+);
 
 // Select widget for the 'default_encrypt' preference
-$_prefs['encryptselect'] = array('type' => 'special');
+$_prefs['encryptselect'] = array(
+    'type' => 'special'
+);
 
 // The default encryption method to use when sending messages
 $_prefs['default_encrypt'] = array(
-    'value' => IMP::ENCRYPT_NONE,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => IMP::ENCRYPT_NONE
+);
 
 // Save attachments when saving in sent-mail folder?
 $_prefs['save_attachments'] = array(
     'value' => 'prompt_no',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         'always' => _("Always save attachments"),
@@ -722,66 +508,109 @@ $_prefs['save_attachments'] = array(
         'never' => _("Never save attachments")
     ),
     'desc' => _("When saving sent-mail, should we save attachment data?"),
-    'help' => 'prefs-save_attachments');
+    'help' => 'prefs-save_attachments'
+);
 
 // Disposition Notification Preferences
 $_prefs['disposition_request_read'] = array(
     'value' => 'ask',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('never' => _("Never"),
-                    'ask' => _("Ask"),
-                    'always' => _("Always")),
+    'enum' => array(
+        'never' => _("Never"),
+        'ask' => _("Ask"),
+        'always' => _("Always")
+    ),
     'desc' => _("Request read receipts?"),
     'help' => 'prefs-disposition_request_read'
 );
 
-// End Message Composition preferences
+// The list of buttons to show in CKeditor
+// See http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Toolbar for
+// details on configuration
+$_prefs['ckeditor_buttons'] = array(
+    'value' => "[['Source','Maximize','-','Templates'],['Cut','Copy','Paste','PasteText','PasteFromWord'],['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],'/',['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],['Link','Unlink'],['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar'],'/',['Styles','Format','Font','FontSize'],['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],['TextColor','BGColor']]",
+    // Use the following line for a very basic set of buttons:
+    // 'value' => "['Bold','Italic','-','NumberedList','BulletedList','-','Link','Unlink']",
+);
+
+
+
+// *** Stationery Preferences ***
+
+$prefGroups['stationery'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Stationery"),
+    'desc' => _("Edit stationery and form responses."),
+    'members' => array('stationerymanagement')
+);
+
+// Stationery configuration widget
+$_prefs['stationerymanagement'] = array(
+    'type' => 'special'
+);
+
+// Internal stationery storage value
+$_prefs['stationery'] = array(
+    // value = serialize(array())
+    'value' => 'a:0:{}'
+);
 
 
-// Message Replies preferences
+
+// *** Compose Reply Preferences ***
+
+$prefGroups['reply'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Message Replies"),
+    'desc' => _("Configure how you reply to mail."),
+    'members' => array(
+        'reply_quote', 'reply_format', 'reply_headers', 'attrib_text'
+    )
+);
 
 // Should the original message be included?
 $_prefs['reply_quote'] = array(
     'value' => 1,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Include original message in a reply?"));
+    'desc' => _("Include original message in a reply?")
+);
 
 // When replying to a message, should we use the same format as the
 // original message?
 $_prefs['reply_format'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("When replying to a message, should we use the same format as the original message?"));
+    'desc' => _("When replying to a message, should we use the same format as the original message?")
+);
 
 // Reply to header summary - leave a brief summary of the header inside
 // the message.
 $_prefs['reply_headers'] = array(
     'desc' => _("Include a brief summary of the header in a reply?"),
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'checkbox');
+    'type' => 'checkbox'
+);
 
 // How should we attribute quoted lines in a reply
 $_prefs['attrib_text'] = array(
     'value' => _("Quoting %f:"),
-    'locked' => false,
-    'shared' => false,
     'type' => 'text',
     'desc' => _("How to attribute quoted lines in a reply"),
-    'help' => 'prefs-attrib_text');
+    'help' => 'prefs-attrib_text'
+);
 
-// End Message Replies preferences
 
 
-// Message Forwards preferences
+// *** Compose Forward Preferences ***
+
+$prefGroups['forward'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Message Forwards"),
+    'desc' => _("Configure how you forward mail."),
+    'members' => array('forward_default', 'forward_format')
+);
 
 // Should the body text of the original message be included?
 // If this preference is locked, the user will not be able to select the
@@ -790,14 +619,14 @@ $_prefs['forward_default'] = array(
     'value' => 'attach',
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         'attach' => _("As attachment"),
         'body' => _("In the body text"),
         'both' => _("As both body text and an attachment")
     ),
-    'desc' => _("How should messages be forwarded by default?"));
+    'desc' => _("How should messages be forwarded by default?")
+);
 
 // When forwarding a message, should we use the same format as the
 // original message (for the body text)?
@@ -805,37 +634,43 @@ $_prefs['forward_format'] = array(
     'value' => 0,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("When forwarding a message in the body text, should we use the same format as the original message?"));
+    'desc' => _("When forwarding a message in the body text, should we use the same format as the original message?")
+);
 
-// End Message Forwards preferences
 
 
-// Message Drafts preferences
+// *** Message Drafts Preferences ***
+
+$prefGroups['drafts'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Message Drafts"),
+    'desc' => _("Configure how to deal with message drafts."),
+    'members' => array(
+        'draftsselect', 'close_draft', 'unseen_drafts', 'auto_save_drafts',
+        'auto_delete_drafts'
+    )
+);
 
 // closing window after saving a draft?
 $_prefs['close_draft'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Should the compose window be closed after saving a draft?"));
+    'desc' => _("Should the compose window be closed after saving a draft?")
+);
 
 // save drafts as seen or unseen
 $_prefs['unseen_drafts'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Save drafts as unseen?"));
+    'desc' => _("Save drafts as unseen?")
+);
 
 // auto-save drafts? value is in minutes, 0 == don't save.
 $_prefs['auto_save_drafts'] = array(
     'value' => 5,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("No"),
@@ -848,73 +683,68 @@ $_prefs['auto_save_drafts'] = array(
 // delete draft after resume & send?
 $_prefs['auto_delete_drafts'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Automatically delete draft after successfully resuming and sending message?")
 );
 
-// End Message Drafts preferences
 
 
-// Message Viewing preferences
+// *** Message Viewing Preferences ***
+
+$prefGroups['viewing'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Message Viewing"),
+    'desc' => _("Configure how messages are displayed."),
+    'members' => array(
+        'filtering', 'strip_attachments', 'html_image_replacement',
+        'html_image_addrbook', 'highlight_text', 'highlight_simple_markup',
+        'show_quoteblocks', 'dim_signature', 'emoticons', 'parts_display',
+        'mail_hdr', 'default_msg_charset', 'disposition_send_mdn'
+    )
+);
 
 // filter message content?
 $_prefs['filtering'] = array(
     'value' => 0,
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Filter message content for profanity?"));
+    'desc' => _("Filter message content for unwanted text (e.g. profanity)?")
+);
 
 // Should we display an icon to strip attachments?
 $_prefs['strip_attachments'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show an icon to allow stripping of attachments from messages?"));
 
 // What should we do with spam messages after reporting them?
 $_prefs['delete_spam_after_report'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("Nothing"),
-        1 => _("Delete message")
+        1 => _("Delete message"),
+        2 => _("Move to spam folder")
     ),
     'desc' => _("What should we do with spam messages after they have been reported as spam?"),
     'help' => 'prefs-delete_spam_after_report'
 );
-if (!$is_pop3) {
-    $_prefs['delete_spam_after_report']['enum'][2] =
-        _("Move to spam folder");
-}
 
 // What should we do with spam messages after reporting them as innocent?
 $_prefs['move_ham_after_report'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
-        0 => _("Nothing")
+        0 => _("Nothing"),
+        1 => _("Move to Inbox")
     ),
     'desc' => _("What should we do with spam messages after they have been reported as innocent?"),
     'help' => 'prefs-move_ham_after_report'
 );
-if (!$is_pop3) {
-    $_prefs['move_ham_after_report']['enum'][1] =
-        _("Move to Inbox");
-}
 
 // Replace image tags in inline viewed HTML messages with blank images?
 $_prefs['html_image_replacement'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Block images in inline viewed HTML messages unless they are specifically requested?"),
     'help' => 'prefs-html_image_replacement'
@@ -924,8 +754,6 @@ $_prefs['html_image_replacement'] = array(
 // sender is in the user's addressbook?
 $_prefs['html_image_addrbook'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Automatically show images in inline viewed HTML messages when the sender is in my address book?"),
     'help' => 'prefs-html_image_addrbook'
@@ -936,24 +764,22 @@ $_prefs['highlight_text'] = array(
     'value' => 1,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Mark different levels of quoting with different colors?"));
+    'desc' => _("Mark different levels of quoting with different colors?")
+);
 
 // should we try to mark simple markup with html tags?
 $_prefs['highlight_simple_markup'] = array(
     'value' => 1,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Mark simple markup?"));
+    'desc' => _("Mark simple markup?")
+);
 
 // should we show large blocks of quoted text or hide them?
 $_prefs['show_quoteblocks'] = array(
     'value' => 'thread',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         'shown' => _("Shown"),
@@ -962,37 +788,36 @@ $_prefs['show_quoteblocks'] = array(
         'listthread' => _("Hidden in Thread View and List Messages"),
         'hidden' => _("Hidden")
     ),
-    'desc' => _("Should large blocks of quoted text be shown or hidden by default? It can be toggled easily whichever you choose."));
+    'desc' => _("Should large blocks of quoted text be shown or hidden by default? It can be toggled easily whichever you choose.")
+);
 
 // should we dim signatures?
 $_prefs['dim_signature'] = array(
     'value' => 0,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Dim signatures?"));
+    'desc' => _("Dim signatures?")
+);
 
 // Convert textual emoticons into graphical ones?
 $_prefs['emoticons'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Convert textual emoticons into graphical ones?"));
+    'desc' => _("Convert textual emoticons into graphical ones?")
+);
 
 // how do we display message parts in the summary?
 $_prefs['parts_display'] = array(
     'value' => 'atc',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         'all' => _("Show all parts"),
         'atc' => _("Show all attachments"),
         'none' => _("Do not show parts")
     ),
-    'desc' => _("Which message parts do you want to display in the summary?"));
+    'desc' => _("Which message parts do you want to display in the summary?")
+);
 
 // Display custom headers (configured via the identity screen) when viewing
 // messages?
@@ -1000,10 +825,9 @@ $_prefs['mail_hdr'] = array(
     // Value is a list of headers to display, separated by "\n"
     // e.g.: "Message-ID\nX-Spam-Level"
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'textarea',
-    'desc' => _("Additional headers to display when viewing: <em>(enter each header on a new line)</em>"));
+    'desc' => _("Additional headers to display when viewing: <em>(enter each header on a new line)</em>")
+);
 
 // default message character set
 $_prefs['default_msg_charset'] = array(
@@ -1012,20 +836,19 @@ $_prefs['default_msg_charset'] = array(
         : (isset($GLOBALS['nls']['charsets'][$GLOBALS['language']])
             ? $GLOBALS['nls']['charsets'][$GLOBALS['language']]
             : ''),
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array_merge(
         array('' => _("Default (US-ASCII)")), Horde_Nls::$config['encodings']
     ),
     'desc' => _("The default charset for messages with no charset information:"),
-    'help' => 'prefs-default_msg_charset');
+    'help' => 'prefs-default_msg_charset'
+);
 
+// Send read receipts?
 $_prefs['disposition_send_mdn'] = array(
     'value' => 1,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("Never send read receipt"),
@@ -1036,75 +859,81 @@ $_prefs['disposition_send_mdn'] = array(
     'help' => 'prefs-disposition_send_mdn'
 );
 
-// End Message Viewing preferences
 
 
-// Deleting and Moving Messages preferences
+// *** Delete/Move Messages Preferences ***
+
+$prefGroups['delmove'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Deleting and Moving Messages"),
+    'desc' => _("Set preferences for what happens when you move and delete messages."),
+    'members' => array(
+        'mailbox_return', 'delete_spam_after_report', 'move_ham_after_report',
+        'empty_spam_menu', 'use_trash', 'trashselect', 'use_vtrash',
+        'empty_trash_menu'
+    )
+);
 
 // should we return to the mailbox listing after deleting a message?
 $_prefs['mailbox_return'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Return to the mailbox listing after deleting, moving, or copying a message?"));
+    'desc' => _("Return to the mailbox listing after deleting, moving, or copying a message?")
+);
 
 // should we move messages to a trash folder instead of just marking
 // them as deleted?
 $_prefs['use_trash'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("When deleting messages, move them to your Trash folder instead of marking them as deleted?"));
+    'desc' => _("When deleting messages, move them to your Trash folder instead of marking them as deleted?")
+);
 
 // use Virtual Trash folder
 $_prefs['use_vtrash'] = array(
-    'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 0
+);
 
 // virtual trash folder identifier
 $_prefs['vtrash_id'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ''
+);
 
 // display the 'Empty Trash' link in the menubar?
 $_prefs['empty_trash_menu'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Display the \"Empty Trash\" link in the menubar?"));
+    'desc' => _("Display the \"Empty Trash\" link in the menubar?")
+);
 
 // display the 'Empty Spam' link in the menubar?
 $_prefs['empty_spam_menu'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Display the \"Empty Spam\" link in the menubar?"));
+    'desc' => _("Display the \"Empty Spam\" link in the menubar?")
+);
 
 // hide deleted
 $_prefs['delhide'] = array(
-    'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 0
+);
+
 
-// End Deleting and Moving Messages preferences
 
+// *** New Mail Notification Preferences ***
 
-// New Mail preferences
+$prefGroups['newmail'] = array(
+    'column' => _("Message Options"),
+    'label' => _("New Mail"),
+    'desc' => _("Control when new mail will be checked for, and whether or not to notify you when it arrives."),
+    'members' => array(
+        'refresh_time', 'nav_poll_all', 'nav_popup', 'soundselect'
+    )
+);
 
 // time before reloading the navigator or mailbox page
 $_prefs['refresh_time'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("Never"),
@@ -1120,27 +949,30 @@ $_prefs['refresh_time'] = array(
 // javascript popup if there's new mail?
 $_prefs['nav_popup'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Display pop-up notification of new mail?"),
 );
 
 // play a sound on new mail? if so, which one?
 $_prefs['nav_audio'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ''
 );
 
 // sound selection widget
-$_prefs['soundselect'] = array('type' => 'special');
+$_prefs['soundselect'] = array(
+    'type' => 'special'
+);
+
 
-// End New Mail preferences
 
+// *** IMAP Flag Preferences ***
 
-// IMAP Flag preferences
+$prefGroups['flags'] = array(
+    'column' => _("Message Options"),
+    'label' => _("Message Flags"),
+    'desc' => _("Configure flag highlighting."),
+    'members' => array('flagmanagement')
+);
 
 // UI for flag management.
 $_prefs['flagmanagement'] = array(
@@ -1271,28 +1103,31 @@ $_prefs['msgflags'] = array(
             // Pursuant to RFC, this flag SHOULD NOT be changed by the user
             't' => 'imap'
         ),
-    )),
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    ))
 );
 
 // The default color to use for flags that don't require row highlighting.
 $_prefs['msgflags_color'] = array(
-    'value' => '#ffffff',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => '#ffffff'
+);
+
 
-// End IMAP Flag preferences
 
-// Display Options preferences
+// *** Mailbox Display Preferences ***
+
+$prefGroups['mboxdisplay'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Mailbox Display Options"),
+    'desc' => _("Change display options such as how many messages you see on each page and how messages are sorted."),
+    'members' => array(
+        'mailbox_start', 'sortby', 'sortdir', 'max_msgs', 'from_link',
+        'time_format', 'atc_flag'
+    )
+);
 
 // Where to start when opening mailbox?
 $_prefs['mailbox_start'] = array(
     'value' => IMP::MAILBOX_START_FIRSTUNSEEN,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         IMP::MAILBOX_START_FIRSTUNSEEN => _("First (oldest) Unseen Message"),
@@ -1301,7 +1136,8 @@ $_prefs['mailbox_start'] = array(
         IMP::MAILBOX_START_LASTPAGE => _("Last Page")
     ),
     'desc' => _("When opening a mailbox for the first time, where do you want to start?"),
-    'help' => 'prefs-mailbox_start');
+    'help' => 'prefs-mailbox_start'
+);
 
 // default sorting column
 $_prefs['sortby'] = array(
@@ -1309,8 +1145,6 @@ $_prefs['sortby'] = array(
     // sort that can be done without parsing message headers. It sorts
     // messages by the order they arrived within the mailbox.
     'value' => Horde_Imap_Client::SORT_SEQUENCE,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         Horde_Imap_Client::SORT_SEQUENCE => _("NONE"),
@@ -1321,27 +1155,25 @@ $_prefs['sortby'] = array(
         Horde_Imap_Client::SORT_SIZE => _("Message Size"),
         Horde_Imap_Client::SORT_THREAD => _("Thread")
     ),
-    'desc' => _("Default sorting criteria:"));
+    'desc' => _("Default sorting criteria:")
+);
 
 // default sorting direction
 $_prefs['sortdir'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("Ascending"),
         1 => _("Descending")
     ),
-    'desc' => _("Default sorting direction:"));
+    'desc' => _("Default sorting direction:")
+);
 
 // sort prefs for individual folders
 $_prefs['sortpref'] = array(
     // value = serialize(array())
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 'a:0:{}'
+);
 
 // default sorting criteria for the date column
 $_prefs['sortdate'] = array(
@@ -1351,7 +1183,6 @@ $_prefs['sortdate'] = array(
     'value' => Horde_Imap_Client::SORT_ARRIVAL,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         Horde_Imap_Client::SORT_ARRIVAL => _("Arrival time on server"),
@@ -1363,41 +1194,25 @@ $_prefs['sortdate'] = array(
 // mailbox constraints
 $_prefs['max_msgs'] = array(
     'value' => 30,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
-    'desc' => _("Messages per page in the mailbox view."));
+    'desc' => _("Messages per page in the mailbox view.")
+);
 
 // How the from field should be displayed on the mailbox screen
 $_prefs['from_link'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("Clicking on the address will compose a new message to the sender"),
         1 => _("Clicking on the address will open the message to be read"),
         2 => _("Do not generate a link in the From: column")
     ),
-    'desc' => _("The From: column of the message should be linked:"));
-
-// Display attachment information in mailbox list.
-// Disabled by default, and not shown to user, because this display requires
-// substantial overhead to parse the message structures of all message in
-// the mailbox list at view time.
-$_prefs['atc_flag'] = array(
-    'value' => 0,
-    // Locked by default
-    'locked' => true,
-    'shared' => false,
-    'type' => 'checkbox',
-    'desc' => _("Display attachment information about a message in the mailbox listing?"));
+    'desc' => _("The From: column of the message should be linked:")
+);
 
 // Time format for messages dated today
 $_prefs['time_format'] = array(
     'value' => '%X',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         '%X' => strftime('%X'),
@@ -1406,13 +1221,37 @@ $_prefs['time_format'] = array(
         '%H:%M' => strftime('%H:%M'),
         '%I:%M%p' => strftime('%I:%M%p'),
     ),
-    'desc' => _("Format of message dates in the mailbox view for messages dated today"));
+    'desc' => _("Format of message dates in the mailbox view for messages dated today")
+);
+
+// Display attachment information in mailbox list.
+// Disabled by default, and not shown to user, because this display requires
+// substantial overhead to parse the message structures of all message in
+// the mailbox list at view time.
+$_prefs['atc_flag'] = array(
+    'value' => 0,
+    // Locked by default
+    'locked' => true,
+    'type' => 'checkbox',
+    'desc' => _("Display attachment information about a message in the mailbox listing?")
+);
+
+
+
+// *** Folder Display Preferences ***
+
+$prefGroups['folderdisplay'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Folder Display Options"),
+    'desc' => _("Change folder navigation display options."),
+    'members' => array(
+        'nav_expanded', 'tree_view', 'nav_expanded_sidebar', 'nav_poll_all'
+    )
+);
 
 // expand folder tree by default
 $_prefs['nav_expanded'] = array(
     'value' => 2,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("No"),
@@ -1424,8 +1263,6 @@ $_prefs['nav_expanded'] = array(
 // folder tree view style
 $_prefs['tree_view'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("Combine all namespaces"),
@@ -1437,115 +1274,148 @@ $_prefs['tree_view'] = array(
 // expand folder tree by default in sidebar
 $_prefs['nav_expanded_sidebar'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         0 => _("No"),
         1 => _("Yes"),
         2 => _("Current expanded status in the folders view")
     ),
-    'desc' => _("Expand the entire folder tree by default in the sidebar?"));
+    'desc' => _("Expand the entire folder tree by default in the sidebar?")
+);
 
 // poll all folders for new mail?
 $_prefs['nav_poll_all'] = array(
     'value' => 0,
-    'locked' => $is_pop3,
-    'shared' => false,
+    'locked' => false,
     'type' => 'checkbox',
-    'desc' => _("Poll all folders for new mail?"));
+    'desc' => _("Poll all folders for new mail?")
+);
 
 // list of folders to expand by default
 $_prefs['expanded_folders'] = array(
     // value = serialize(array())
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 'a:0:{}'
+);
 
 // list of folders to poll for new mail
 $_prefs['nav_poll'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ''
+);
+
+
+
+// *** Filter Preferences ***
+
+$prefGroups['filters'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Filters"),
+    'desc' => _("Create filtering rules to organize your incoming mail, sort it into folders, and delete spam."),
+    'members' => array(
+        'filters_link', 'filters_blacklist_link', 'filters_whitelist_link',
+        'filter_on_login', 'filter_on_display', 'filter_any_mailbox',
+        'filter_menuitem'
+    )
+);
 
-// End Display Options preferences
+$_prefs['filters_link'] = array(
+    'type' => 'link',
+    'url' => $GLOBALS['registry']->link('mail/showFilters'),
+    'img' => 'filters.png',
+    'desc' => _("Edit your Filter Rules"),
+    'help' => 'filter-edit-rules'
+);
 
+$_prefs['filters_blacklist_link'] = array(
+    'type' => 'link',
+    'img' => 'filters.png',
+    'url' => $GLOBALS['registry']->link('mail/showBlacklist'),
+    'desc' => _("Edit your Blacklist"),
+    'help' => 'filter-edit-blacklist'
+);
 
-// Filter preferences
+$_prefs['filters_whitelist_link'] = array(
+    'type' => 'link',
+    'img' => 'filters.png',
+    'url' => $GLOBALS['registry']->link('mail/showWhitelist'),
+    'desc' => _("Edit your Whitelist"),
+    'help' => 'filter-edit-whitelist'
+);
 
 // run filters on login?
 $_prefs['filter_on_login'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Apply filter rules upon logging on?"),
+    'help' => 'filter-on-login'
+);
 
 // run filters with INBOX display?
 $_prefs['filter_on_display'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Apply filter rules whenever Inbox is displayed?"),
+    'help' => 'filter-on-display'
+);
 
-// run filters when sidebar updates?
-$_prefs['filter_on_sidebar'] = array(
+// Allow filters to be applied to any mailbox?
+$_prefs['filter_any_mailbox'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Allow filter rules to be applied in any mailbox?"),
+    'help' => 'filter-any-mailbox'
+);
 
 // show filter icon on the menubar?
 $_prefs['filter_menuitem'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Show the filter icon on the menubar?"),
+    'help' => 'filter-menuitem'
+);
 
-// Allow filters to be applied to any mailbox?
-$_prefs['filter_any_mailbox'] = array(
-    'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
 
-// End Filter preferences
 
+// *** Addressbook Preferences ***
 
-// Address book preferences
+$prefGroups['addressbooks'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Address Books"),
+    'desc' => _("Select address book sources for adding and searching for addresses."),
+   'members' => array(
+        'save_recipients', 'display_contact', 'sourceselect', 'add_source'
+    )
+);
 
 // Should recipients of outgoing messages be added automatically to
 // the address book?
 $_prefs['save_recipients'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
-    'desc' => _("Save recipients automatically to the default address book?"));
+    'desc' => _("Save recipients automatically to the default address book?")
+);
 
 // By default, display all contacts in the address book when loading
 // the contacts screen.  If your default address book is large and
 // slow to display, you may want to disable and lock this option.
 $_prefs['display_contact'] = array(
     'value' => 1,
-    'locked' => false,
     'shared' => true,
     'type' => 'checkbox',
-    'desc' => _("List all contacts when loading the contacts screen? (if disabled, you will only see contacts that you search for explicitly)"));
+    'desc' => _("List all contacts when loading the contacts screen? (if disabled, you will only see contacts that you search for explicitly)")
+);
 
 // address book selection widget
-$_prefs['sourceselect'] = array('type' => 'special');
+$_prefs['sourceselect'] = array(
+    'type' => 'special'
+);
 
 // address book(s) to use when expanding addresses
 // You can provide default values this way (note the \t and the double quotes):
 // 'value' => "source_one\tsource_two"
 // refer to turba/config/sources.php for possible source values
 $_prefs['search_sources'] = array(
-    'value' => "",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ""
+);
 
 // field(s) to use when expanding addresses
 // This depends on the search_sources preference if you want to provide
@@ -1555,126 +1425,175 @@ $_prefs['search_sources'] = array(
 // 'field_three' in source_two.
 // refer to turba/config/sources.php for possible source and field values
 $_prefs['search_fields'] = array(
-    'value' => "",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ""
+);
 
 // address book to use for adding addresses
 // put $cfgSources array element name in the value field.
 // Setting value to localsql would allow you to add contacts to MySQL database
 // See turba/config/sources.php for more info
 $_prefs['add_source'] = array(
-    'value' => '',
 //  'value' => 'localsql',
-    'locked' => false,
-    'shared' => true,
-    'type' => 'implicit'
+    'value' => '',
+    'shared' => true
+    'type' => 'enum',
+    'desc' => _("Choose the address book to use when adding addresses.")
 );
 
-// End Address book preferences
 
 
-// Event preferences
+// *** Event Request Preferences ***
+
+$prefGroups['events'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Event Requests"),
+    'desc' => _("Configure how event or meeting requests should be handled."),
+    'members' => array('conflict_interval')
+);
 
 // Amount of minutes to consider a event as a non-conflicting one in iTip
 $_prefs['conflict_interval'] = array(
     'value' => 30,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Minutes needed to consider a event as a non-conflicting one in iTip")
 );
 
-// End Calendar preferences
 
 
-// PGP options
+// *** PGP Preferences ***
+
+$prefGroups['pgp'] = array(
+    'column' => _("Other Options"),
+    'label' => _("PGP Options"),
+    'desc' => sprintf(_("Control PGP support for %s."), $GLOBALS['registry']->get('name')),
+    'members' => array(
+        'use_pgp', 'use_pgp_text', 'pgp_attach_pubkey', 'pgp_scan_body',
+        'pgp_verify', 'pgppublickey', 'pgpprivatekey'
+    )
+);
 
 // Activate PGP support?
 $_prefs['use_pgp'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'type' => 'checkbox',
+    'desc' => _("Enable PGP functionality?"),
+    'help' => 'pgp-overview'
+);
+
+$_prefs['use_pgp_text'] = array(
+    'value' => '<div class="prefsPgpWarning">' . _("PGP support requires popup windows to be used.  If your browser is currently set to disable popup windows, you must change this setting or else the PGP features will not work correctly.") . '</div>',
+    'type' => 'rawhtml'
 );
 
-// You should not manually change the rest of the PGP entries
 $_prefs['pgp_attach_pubkey'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Should your PGP public key to be attached to your messages by default?"),
+    'help' => 'pgp-option-attach-pubkey'
+);
 
 $_prefs['pgp_scan_body'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Should the body of text/plain messages be scanned for PGP data?"),
+    'help' => 'pgp-option-scan-body'
+);
 
 $_prefs['pgp_verify'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Should PGP signed messages automatically be verified when viewed?"),
+    'help' => 'pgp-option-verify'
+);
 
-$_prefs['pgp_private_key'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+$_prefs['pgppublickey'] = array(
+    'type' => 'special'
+);
 
 $_prefs['pgp_public_key'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ''
+);
+
+$_prefs['pgpprivatekey'] = array(
+    'type' => 'special'
+);
+
+$_prefs['pgp_private_key'] = array(
+    'value' => ''
+);
+
+
 
-// End PGP Options
+// *** S/MIME Preferences ***
 
-// S/MIME options
+$prefGroups['smime'] = array(
+    'column' => _("Other Options"),
+    'label' => _("S/MIME Options"),
+    'desc' => sprintf(_("Control S/MIME support for %s."), $GLOBALS['registry']->get('name')),
+    'members' => array(
+        'use_smime', 'use_smime_text', 'smime_verify', 'smimepublickey',
+        'smimeprivatekey'
+    )
+);
 
 // Activate S/MIME support?
 $_prefs['use_smime'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Enable S/MIME functionality?"),
+    'help' => 'smime-overview'
+);
+
+$_prefs['use_smime_text'] = array(
+    'value' => '<div class="prefsSmimeWarning">' . _("S/MIME support requires popup windows to be used.  If your browser is currently set to disable popup windows, you must change this setting or else the S/MIME features will not work correctly.") . '</div>',
+    'type' => 'rawhtml'
+);
 
-// You should not manually change the rest of the S/MIME entries
 $_prefs['smime_verify'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'type' => 'checkbox',
+    'desc' => _("Should S/MIME signed messages automatically be verified when viewed?"),
+    'help' => 'smime-option-verify'
+);
 
-$_prefs['smime_private_key'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+// S/MIME public key management widget
+$_prefs['smimepublickey'] = array(
+    'type' => 'special'
+);
 
 $_prefs['smime_public_key'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ''
+);
+
+// S/MIME private key management widget
+$_prefs['smimeprivatekey'] = array(
+    'type' => 'special'
+);
+
+$_prefs['smime_private_key'] = array(
+    'value' => ''
+);
 
 $_prefs['smime_additional_cert'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => ''
+);
+
 
-// End S/MIME Options
 
-// Minimal View Options
+// *** Mobile View (MIMP) Preferences ***
+
+$prefGroups['mimp'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Mobile View Options"),
+    'desc' => _("Configure options for the mobile view."),
+    'members' => array(
+        'mimp_preview_msg', 'mimp_download_confirm', 'mimp_inline_all'
+    )
+);
 
 // display only the first 250 characters of a message on first message view?
 $_prefs['mimp_preview_msg'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Display only the first 250 characters of a message initially?")
 );
@@ -1683,7 +1602,6 @@ $_prefs['mimp_download_confirm'] = array(
     'value' => 0,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Only show download confirmation page if message part is greater than this size, in bytes. Set to 0 to always require the confirmation page.")
 );
@@ -1692,14 +1610,23 @@ $_prefs['mimp_inline_all'] = array(
     'value' => 0,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show all inline parts by default in message view? If unchecked, will treat all but the first viewable inline part as attachments.")
 );
 
-// End Minimal View Options
 
-// Standard View Options
+
+// *** Standard View (IMP) Preferences ***
+
+$prefGroups['standard'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Standard View Options"),
+    'desc' => _("Configure options for the standard view."),
+    'members' => array(
+        'preview_enabled', 'preview_maxlen', 'preview_strip_nl',
+        'preview_show_unread', 'preview_show_tooltip'
+    )
+);
 
 // Previews are disabled by default as it can be performance intensive,
 // especially without caching.
@@ -1707,7 +1634,6 @@ $_prefs['preview_enabled'] = array(
     // Disabled and locked by default
     'value' => 0,
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Enable message previews?")
 );
@@ -1716,7 +1642,6 @@ $_prefs['preview_maxlen'] = array(
     'value' => 250,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         100 => _("100 characters"),
@@ -1731,7 +1656,6 @@ $_prefs['preview_strip_nl'] = array(
     'value' => 1,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Strip linebreaks?")
 );
@@ -1740,7 +1664,6 @@ $_prefs['preview_show_unread'] = array(
     'value' => 1,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show previews for unread messages only?")
 );
@@ -1749,20 +1672,24 @@ $_prefs['preview_show_tooltip'] = array(
     'value' => 0,
     // Locked by default
     'locked' => true,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show previews in tooltips?")
 );
 
-// End Standard View Options
 
-// Dynamic View Options
+
+// *** Dynamic View (DIMP) Preferences ***
+
+$prefGroups['dimp'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Dynamic View Options"),
+    'desc' => _("Configure options for the dynamic view."),
+    'members' => array('dimp_login_view')
+);
 
 // Login preferences (dimp)
 $_prefs['dimp_login_view'] = array(
     'value' => 'portal',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         'portal' => _("Portal"),
@@ -1771,38 +1698,19 @@ $_prefs['dimp_login_view'] = array(
     'desc' => _("The page to view immediately after login.")
 );
 
-// Other implicit dynamic view preferences
+// Other dynamic view preferences
 $_prefs['dimp_qsearch_field'] = array(
-    'value' => 'all',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 'all'
+);
 
 $_prefs['dimp_show_preview'] = array(
-    'value' => true,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => true
+);
 
 $_prefs['dimp_splitbar'] = array(
-    'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 0
+);
 
 $_prefs['dimp_toggle_headers'] = array(
-    'value' => 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
-
-// End Dynamic View Options
-
-// Other entries (used internally in IMP)
-
-// virtual inbox identifier
-$_prefs['vinbox_id'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit');
+    'value' => 0
+);
index 2dd8cd1..ebeef82 100644 (file)
@@ -40,7 +40,7 @@ if (!isset($vars->formname)) {
     $vars->formname = 'compose';
 }
 
-$search_params = IMP_Compose::getAddressSearchParams();
+$search_params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
 $apiargs = array(
     'addresses' => array($vars->search),
     'addressbooks' => array($vars->source),
index dd6f6e9..405e3fd 100644 (file)
@@ -64,6 +64,7 @@ your ``config/prefs.php`` file and your preferences backend::
 
    alternative_display
    attachment_display
+   filter_on_sidebar
    forward_bodytext
 
 
diff --git a/imp/filterprefs.php b/imp/filterprefs.php
deleted file mode 100644 (file)
index cbda88b..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-<?php
-/**
- * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author  Michael Slusarz <slusarz@horde.org>
- * @package IMP
- */
-
-require_once dirname(__FILE__) . '/lib/Application.php';
-Horde_Registry::appInit('imp');
-
-/* Are preferences locked? */
-$login_locked = $prefs->isLocked('filter_on_login') || empty($_SESSION['imp']['filteravail']);
-$display_locked = $prefs->isLocked('filter_on_display') || empty($_SESSION['imp']['filteravail']);
-$sidebar_locked = $prefs->isLocked('filter_on_sidebar') || empty($_SESSION['imp']['filteravail']);
-$anymailbox_locked = $prefs->isLocked('filter_any_mailbox') || empty($_SESSION['imp']['filteravail']);
-$menuitem_locked = $prefs->isLocked('filter_menuitem');
-
-/* Run through the action handlers. */
-$actionID = Horde_Util::getFormData('actionID');
-switch ($actionID) {
-case 'update_prefs':
-    if (!$login_locked) {
-        $prefs->setValue('filter_on_login', Horde_Util::getFormData('filter_login') ? 1 : 0);
-    }
-    if (!$display_locked) {
-        $prefs->setValue('filter_on_display', Horde_Util::getFormData('filter_display') ? 1 : 0);
-    }
-    if (!$sidebar_locked) {
-        $prefs->setValue('filter_on_sidebar', Horde_Util::getFormData('filter_sidebar') ? 1 : 0);
-    }
-    if (!$anymailbox_locked) {
-        $prefs->setValue('filter_any_mailbox', Horde_Util::getFormData('filter_any_mailbox') ? 1 : 0);
-    }
-    if (!$menuitem_locked) {
-        $prefs->setValue('filter_menuitem', Horde_Util::getFormData('filter_menuitem') ? 1 : 0);
-    }
-    $notification->push(_("Preferences successfully updated."), 'horde.success');
-    break;
-}
-
-$chunk = Horde_Util::nonInputVar('chunk');
-$group = 'filters';
-Horde_Prefs_Ui::generateHeader('imp', null, null, $chunk);
-
-$t = $injector->createInstance('Horde_Template');
-$t->setOption('gettext', true);
-$t->set('navcell', Horde_Util::bufferOutput(array('Horde_Prefs_Ui', 'generateNavigationCell'), 'imp', 'filters'));
-$t->set('prefsurl', Horde::getServiceLink('options', 'imp'));
-$t->set('return_text', _("Return to Options"));
-
-/* Get filter links. */
-$blacklist_link = $whitelist_link = $filters_link = false;
-if ($registry->hasMethod('mail/showBlacklist')) {
-    $blacklist_link = $registry->link('mail/showBlacklist');
-}
-if ($registry->hasMethod('mail/showWhitelist')) {
-    $whitelist_link = $registry->link('mail/showWhitelist');
-}
-if ($registry->hasMethod('mail/showFilters')) {
-    $filters_link = $registry->link('mail/showFilters');
-}
-
-/* If filters are disabled. */
-if (!$blacklist_link && !$whitelist_link && !$filters_link) {
-    $t->set('notactive', true);
-} else {
-    $t->set('selfurl', Horde::applicationUrl('filterprefs.php'));
-    $t->set('forminput', Horde_Util::formInput());
-    $t->set('group', $group);
-    $t->set('app', $app);
-
-    $link_array = array(
-        array('g' => _("Edit your Filter Rules"), 'l' => $filters_link, 'h' => 'filter-edit-rules'),
-        array('g' => _("Edit your Blacklist"), 'l' => $blacklist_link, 'h' => 'filter-edit-blacklist'),
-        array('g' => _("Edit your Whitelist"), 'l' => $whitelist_link, 'h' => 'filter-edit-whitelist')
-    );
-    $links = array();
-    foreach ($link_array as $key => $val) {
-        if ($val['l']) {
-            $links[] = array(
-                'img' => Horde::img('filters.png', $val['g']),
-                'link' => Horde::link(Horde::url($val['l'])),
-                'help' => Horde_Help::link('imp', $val['h']),
-                'text' => $val['g']
-            );
-        }
-    }
-    $t->set('links', $links);
-
-    $options_array = array(
-        'login' => array('g' => _("Apply filter rules upon logging on?"), 'p' => 'filter_on_login', 'h' => 'filter-on-login', 'l' => $login_locked),
-        'display' => array('g' => _("Apply filter rules whenever Inbox is displayed?"), 'p' => 'filter_on_display', 'h' => 'filter-on-display', 'l' => $display_locked),
-        'sidebar' => array('g' => _("Apply filter rules whenever sidebar is refreshed?"), 'p' => 'filter_on_sidebar', 'h' => 'filter-on-sidebar', 'l' => $sidebar_locked),
-        'any_mailbox' => array('g' => _("Allow filter rules to be applied in any mailbox?"), 'p' => 'filter_any_mailbox', 'h' => 'filter-any-mailbox', 'l' => $anymailbox_locked),
-        'menuitem' => array('g' => _("Show the filter icon on the menubar?"), 'p' => 'filter_menuitem', 'l' => $menuitem_locked)
-    );
-
-    if ($_SESSION['imp']['protocol'] == 'pop') {
-        unset($options_array['any_mailbox']);
-    }
-
-    $opts = array();
-    foreach ($options_array as $key => $val) {
-        if (!$val['l']) {
-            $opts[] = array(
-                'key' => $key,
-                'checked' => $prefs->getValue($val['p']),
-                'label' => Horde::label('filter_' . $key, $val['g']),
-                'help' => isset($val['h']) ? Horde_Help::link('imp', $val['h']) : null
-            );
-        }
-    }
-    $t->set('opts', $opts);
-    if (!empty($opts)) {
-        $t->set('save_opts', _("Save Options"));
-    }
-}
-
-echo $t->fetch(IMP_TEMPLATES . '/prefs/filters/filters.html');
-if (!$chunk) {
-    require $registry->get('templates', 'horde') . '/common-footer.inc';
-}
index 1a7a655..2247546 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Provides the javascript for the acl.php script (standard view).
+ * Provides the javascript for the ACL preferences management view.
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
diff --git a/imp/js/addressbooksprefs.js b/imp/js/addressbooksprefs.js
deleted file mode 100644 (file)
index 5c39914..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
- * Provides the javascript for managing addressbooks.
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpAddressbooksPrefs = {
-    // Variables set by other code: fields
-
-    deselectHeaders: function()
-    {
-        $('unselected_search_sources').selectedIndex = $('selected_search_sources').selectedIndex = -1;
-    },
-
-    resetHidden: function()
-    {
-        $('search_sources').setValue($A($('selected_search_sources').options).slice(1).pluck('value').join("\t"));
-    },
-
-    addSource: function()
-    {
-        this._sourceAction($('unselected_search_sources'), $('selected_search_sources'));
-    },
-
-    removeSource: function()
-    {
-        this._sourceAction($('selected_search_sources'), $('unselected_search_sources'));
-    },
-
-    _sourceAction: function(from, to)
-    {
-        var i = 1;
-
-        $A(from.options).slice(1).each(function(s) {
-            if (s.selected) {
-                to.appendChild(s.cloneNode(true));
-                s.remove();
-            }
-            ++i;
-        });
-
-        this.resetHidden();
-    },
-
-    moveSourceUp: function()
-    {
-        var sss = $('selected_search_sources'),
-            sel = sss.selectedIndex;
-
-        if (sel == -1 || sss.length <= 2) {
-            return;
-        }
-
-        // Deselect everything but the first selected item
-        sss.selectedIndex = sel;
-
-        sss.options[sel].previous().insert({ before: sss.options[sel].cloneNode(false) });
-        sss.options[sel].remove();
-
-        this.resetHidden();
-    },
-
-    moveSourceDown: function()
-    {
-        var i,
-            sss = $('selected_search_sources'),
-            sel = sss.selectedIndex,
-            l = sss.length,
-            tmp = [];
-
-        if (sel == -1 || l <= 2) {
-            return;
-        }
-
-        // deselect everything but the first selected item
-        sss.selectedIndex = sel;
-
-        sss.options[sel].next().insert({ after: sss.options[sel].cloneNode(false) });
-        sss.options[sel].remove();
-
-        this.resetHidden();
-    },
-
-    updateSearchFields: function()
-    {
-        var sv = this._getSelectedValue(false),
-            sf = $('search_fields');
-
-        sf.update('');
-        this.fields.each(function(f) {
-            if (f[0] == sv) {
-                f.slice(1).each(function(o) {
-                    var tmp = new Option(o[1], o[0]);
-                    if (o[2]) {
-                        tmp.selected = true;
-                    }
-                    sf.insert(tmp);
-                });
-            }
-        });
-
-        this.changeSearchFields();
-    },
-
-    _getSelectedValue: function(index)
-    {
-        var sss = $('selected_search_sources');
-        if (sss) {
-            if (index) {
-                return sss.selectedIndex;
-            }
-            if (sss.selectedIndex >= 0) {
-                return sss.options[sss.selectedIndex].value;
-            }
-            return '';
-        } else {
-            return index ? 0 : this.fields[0][0];
-        }
-    },
-
-    changeSearchFields: function()
-    {
-        var data = [],
-            i = 0,
-            sf = $('search_fields'),
-            sv = this._getSelectedValue(true);
-
-        $A(sf.options).each(function(o) {
-            this.fields[sv][i][2] = o.selected;
-            ++i;
-        }.bind(this));
-
-        this.fields.each(function(f) {
-            var tmp = [ f[0] ];
-            f.slice(1).each(function(o) {
-                if (o[2]) {
-                    tmp.push(o[0]);
-                }
-            });
-            data.push(tmp.join("\t"));
-        });
-        $('search_fields_string').setValue(data.join("\n"));
-    },
-
-    onDomLoad: function()
-    {
-        this.updateSearchFields();
-
-        if ($('search_fields')) {
-            $('search_fields').observe('change', this.changeSearchFields.bind(this));
-        }
-
-        if ($('unselected_search_sources')) {
-            //$('unselected_search_sources').observe('change', this.deselectHeaders.bind(this));
-            $('selected_search_sources').observe('change', function() {
-                //this.deselectHeaders();
-                this.updateSearchFields();
-            }.bind(this));
-            $('addsource').observe('click', this.addSource.bind(this));
-            $('removesource').observe('click', this.removeSource.bind(this));
-            $('moveup').observe('click', this.moveSourceUp.bind(this));
-            $('movedown').observe('click', this.moveSourceDown.bind(this));
-        }
-    }
-
-};
-
-document.observe('dom:loaded', ImpAddressbooksPrefs.onDomLoad.bind(ImpAddressbooksPrefs));
index a848bcb..cad00ec 100644 (file)
@@ -40,7 +40,7 @@ class IMP_Ajax_Imple_ContactAutoCompleter extends Horde_Ajax_Imple_AutoCompleter
 
         if ($ac_browser && !isset($_SESSION['imp']['cache']['ac_ajax'])) {
             $success = $use_ajax = true;
-            $sparams = IMP_Compose::getAddressSearchParams();
+            $sparams = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
             foreach ($sparams['fields'] as $val) {
                 array_map('strtolower', $val);
                 sort($val);
index ef334a8..77608d3 100644 (file)
@@ -56,13 +56,6 @@ class IMP_Application extends Horde_Registry_Application
     public $version = 'H4 (5.0-git)';
 
     /**
-     * Cached data for prefs pages.
-     *
-     * @var array
-     */
-    static public $prefsCache = array();
-
-    /**
      * Constructor.
      */
     public function __construct()
@@ -414,556 +407,65 @@ class IMP_Application extends Horde_Registry_Application
         return $auth->listUsers();
     }
 
-    /* Preferences display/handling methods. */
+    /* Preferences display/handling methods. Code is contained in
+     * IMP_Prefs_Ui so it doesn't have to be loaded on every page load. */
 
     /**
-     * Code to run when viewing prefs for this application.
+     * Code to run on init when viewing prefs for this application.
      *
-     * @param string $group  The prefGroup name.
-     *
-     * @return array  A list of variables to export to the prefs display page.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsInit($group)
+    public function prefsInit($ui)
     {
-        /* Add necessary javascript files here (so they are added to the
-         * document HEAD). */
-        switch ($group) {
-        case 'accounts':
-            Horde::addScriptFile('accountsprefs.js', 'imp');
-
-            Horde::addInlineScript(array(
-                'ImpAccountsPrefs.confirm_delete = ' . Horde_Serialize::serialize(_("Are you sure you want to delete this account?"), Horde_Serialize::JSON, Horde_Nls::getCharset())
-            ));
-            break;
-
-        case 'addressbooks':
-            $this->_prefsPrepareSourceselect();
-            break;
-
-        case 'display':
-            /* Set the timezone on this page so the 'time_format' output uses
-             * the configured time zone's time, not the system's time zone. */
-            Horde_Nls::setTimeZone();
-            break;
-
-        case 'flags':
-            Horde::addScriptFile('colorpicker.js', 'horde');
-            Horde::addScriptFile('flagprefs.js', 'imp');
-
-            Horde::addInlineScript(array(
-                'ImpFlagPrefs.new_prompt = ' . Horde_Serialize::serialize(_("Please enter the label for the new flag:"), Horde_Serialize::JSON, Horde_Nls::getCharset()),
-                'ImpFlagPrefs.confirm_delete = ' . Horde_Serialize::serialize(_("Are you sure you want to delete this flag?"), Horde_Serialize::JSON, Horde_Nls::getCharset())
-            ));
-            break;
-
-        case 'identities':
-            if (!$GLOBALS['prefs']->isLocked('sent_mail_folder')) {
-                Horde::addScriptFile('folderprefs.js', 'imp');
-                Horde::addInlineScript(array(
-                    'ImpFolderPrefs.folders = ' . Horde_Serialize::serialize(array('sent_mail_folder', 'sent_mail_new', _("Enter the name for your new sent-mail folder"), _("Create a new sent-mail folder")), Horde_Serialize::JSON, Horde_Nls::getCharset())
-                ));
-            }
-            break;
-
-        case 'server':
-            $code = array();
-
-            if (!$GLOBALS['prefs']->isLocked('drafts_folder')) {
-                $code[] = array('drafts', 'drafts_new', _("Enter the name for your new drafts folder"), _("Create a new drafts folder"));
-            }
-
-            if (!$GLOBALS['prefs']->isLocked('spam_folder')) {
-                $code[] = array('spam', 'spam_new', _("Enter the name for your new spam folder"), _("Create a new spam folder"));
-            }
-
-            if (!$GLOBALS['prefs']->isLocked('trash_folder') &&
-                !$GLOBALS['prefs']->isLocked('use_vtrash')) {
-                $code[] = array('trash', 'trash_new', _("Enter the name for your new trash folder"), _("Create a new trash folder"));
-            }
-
-            if (!empty($code)) {
-                Horde::addScriptFile('folderprefs.js', 'imp');
-                Horde::addInlineScript(array(
-                    'ImpFolderPrefs.folders = ' . Horde_Serialize::serialize($code, Horde_Serialize::JSON, Horde_Nls::getCharset())
-                ));
-            }
-            break;
-        }
+        $GLOBALS['injector']->getInstance('IMP_Prefs_Ui')->prefsInit($ui);
     }
 
     /**
-     * Special preferences handling on update.
+     * Generate code used to display a special preference.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
-     * @return boolean  True if preference was updated.
+     * @return string  The HTML code to display on the options page.
      */
-    public function prefsSpecial($item, $updated)
+    public function prefsSpecial($ui, $item)
     {
-        switch ($item) {
-        case 'sentmailselect':
-            return $this->_prefsSentmailSelect($updated);
-
-        case 'draftsselect':
-            return $updated | $this->_prefsSpecialFolders($updated, 'drafts_folder', 'drafts', 'drafts_new');
-
-        case 'spamselect':
-            return $updated | $this->_prefsSpecialFolders($updated, 'spam_folder', 'spam', 'spam_new');
-
-        case 'trashselect':
-            return $this->_prefsTrashSelect($updated);
-
-        case 'sourceselect':
-            return $this->_prefsSourceSelect($updated);
-
-        case 'initialpageselect':
-            $this->_prefsInitialPageSelect();
-            return true;
-
-        case 'encryptselect':
-            $this->_prefsEncryptSelect();
-            return true;
-
-        case 'soundselect':
-            return $GLOBALS['prefs']->setValue('nav_audio', Horde_Util::getFormData('nav_audio'));
-
-        case 'flagmanagement':
-            $this->_prefsFlagManagement();
-            return false;
-
-        case 'accountsmanagement':
-            $this->_prefsAccountsManagement();
-            return false;
-        }
+        return $GLOBALS['injector']->getInstance('IMP_Prefs_Ui')->prefsSpecial($ui, $item);
     }
 
     /**
-     * Special preferences handling on UI display.
+     * Special preferences handling on update.
      *
-     * @param string $item  The preference name.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
-     * @return boolean  True if the preference item should be displayed.
+     * @return boolean  True if preference was updated.
      */
-    public function prefsSpecialGenerate($item)
+    public function prefsSpecialUpdate($ui, $item)
     {
-        switch ($item) {
-        case 'sentmailselect':
-            return !$GLOBALS['prefs']->isLocked('sent_mail_folder');
-
-        case 'draftsselect':
-            return !$GLOBALS['prefs']->isLocked('drafts_folder');
-
-        case 'spamselect':
-            return !$GLOBALS['prefs']->isLocked('spam_folder');
-
-        case 'trashselect':
-            return (!$GLOBALS['prefs']->isLocked('trash_folder') && !$GLOBALS['prefs']->isLocked('use_vtrash'));
-
-        case 'initialpageselect':
-            return !$GLOBALS['prefs']->isLocked('initial_page');
-
-        case 'encryptselect':
-            return !$GLOBALS['prefs']->isLocked('default_encrypt');
-
-        case 'soundselect':
-            return !$GLOBALS['prefs']->isLocked('nav_audio');
-
-        case 'accountsmanagement':
-            $GLOBALS['prefsui_no_save'] = true;
-            return !empty($GLOBALS['conf']['user']['allow_accounts']);
-
-        default:
-            return true;
-        }
+        return $GLOBALS['injector']->getInstance('IMP_Prefs_Ui')->prefsSpecialUpdate($ui, $item);
     }
 
     /**
-     * Do anything that we need to do as a result of certain preferences
-     * changing.
+     * Called when preferences are changed.
      *
-     * @param string $group  The prefGroup name.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsCallback($group)
+    public function prefsCallback($ui)
     {
-        global $prefs;
-
-        /* Always check to make sure we have a valid trash folder if delete to
-         * trash is active. */
-        if (($prefs->isDirty('use_trash') || $prefs->isDirty('trash_folder')) &&
-            $prefs->getValue('use_trash') &&
-            !$prefs->getValue('trash_folder') &&
-            !$prefs->getValue('use_vtrash')) {
-            $GLOBALS['notification']->push(_("You have activated move to Trash but no Trash folder is defined. You will be unable to delete messages until you set a Trash folder in the preferences."), 'horde.warning');
-        }
-
-        switch ($group) {
-        case 'compose':
-            if ($prefs->isDirty('mail_domain')) {
-                $maildomain = preg_replace('/[^-\.a-z0-9]/i', '', $prefs->getValue('mail_domain'));
-                $prefs->setValue('maildomain', $maildomain);
-                if (!empty($maildomain)) {
-                    $_SESSION['imp']['maildomain'] = $maildomain;
-                }
-            }
-
-            if ($prefs->isDirty('compose_popup')) {
-                Horde::addInlineScript(array(
-                    'if (window.parent.frames.horde_menu) window.parent.frames.horde_menu.location.reload();'
-                ));
-            }
-            break;
-
-        case 'delmove':
-            if ($prefs->isDirty('use_vtrash')) {
-                $GLOBALS['imp_search']->initialize(true);
-            }
-            break;
-
-        case 'display':
-            if ($prefs->isDirty('tree_view')) {
-                $this->_mailboxesChanged();
-            }
-            break;
-
-        case 'server':
-            if ($prefs->isDirty('use_vinbox')) {
-                $GLOBALS['imp_search']->initialize(true);
-            }
-
-            if ($prefs->isDirty('subscribe')) {
-                $this->_mailboxesChanged();
-            }
-            break;
-        }
+        $GLOBALS['injector']->getInstance('IMP_Prefs_Ui')->prefsCallback($ui);
     }
 
     /**
      * Generate the menu to use on the prefs page.
      *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
      * @return Horde_Menu  A Horde_Menu object.
      */
-    public function prefsMenu()
-    {
-        return IMP::getMenu();
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsSentmailSelect($updated)
-    {
-        if (!$GLOBALS['conf']['user']['allow_folders'] ||
-            $GLOBALS['prefs']->isLocked('sent_mail_folder')) {
-            return $updated;
-        }
-
-        $sent_mail_folder = Horde_Util::getFormData('sent_mail_folder');
-        $sent_mail_new = Horde_String::convertCharset(Horde_Util::getFormData('sent_mail_new'), Horde_Nls::getCharset(), 'UTF7-IMAP');
-        $sent_mail_default = $GLOBALS['prefs']->getValue('sent_mail_folder');
-
-        if (empty($sent_mail_folder) && !empty($sent_mail_new)) {
-            $sent_mail_folder = $GLOBALS['imp_imap']->appendNamespace($sent_mail_new);
-        } elseif (($sent_mail_folder == '-1') && !empty($sent_mail_default)) {
-            $sent_mail_folder = $GLOBALS['imp_imap']->appendNamespace($sent_mail_default);
-        }
-
-        if (!empty($sent_mail_folder)) {
-            $imp_folder = $GLOBALS['injector']->getInstance('IMP_Folder');
-            if (!$imp_folder->exists($sent_mail_folder)) {
-                $imp_folder->create($sent_mail_folder, $GLOBALS['prefs']->getValue('subscribe'));
-            }
-        }
-        $GLOBALS['identity']->setValue('sent_mail_folder', IMP::folderPref($sent_mail_folder, false));
-
-        return true;
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsSpecialFolders($updated, $pref, $folder, $new)
+    public function prefsMenu($ui)
     {
-        if (!$GLOBALS['conf']['user']['allow_folders']) {
-            return $updated;
-        }
-
-        $folder = Horde_Util::getFormData($folder);
-        if (isset($folder) && !$GLOBALS['prefs']->isLocked($pref)) {
-            $new = Horde_String::convertCharset(Horde_Util::getFormData($new), Horde_Nls::getCharset(), 'UTF7-IMAP');
-            if ($folder == IMP::PREF_NO_FOLDER) {
-                $GLOBALS['prefs']->setValue($pref, '');
-            } else {
-                if (empty($folder) && !empty($new)) {
-                    $folder = $GLOBALS['imp_imap']->appendNamespace($new);
-                    if (!$GLOBALS['injector']->getInstance('IMP_Folder')->create($folder, $GLOBALS['prefs']->getValue('subscribe'))) {
-                        $folder = null;
-                    }
-                }
-                if (!empty($folder)) {
-                    $GLOBALS['prefs']->setValue($pref, IMP::folderPref($folder, false));
-                    return true;
-                }
-            }
-        }
-
-        return $updated;
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsTrashSelect($updated)
-    {
-        global $prefs;
-
-        if (Horde_Util::getFormData('trash') == IMP::PREF_VTRASH) {
-            if ($prefs->isLocked('use_vtrash')) {
-                return false;
-            }
-
-            $prefs->setValue('use_vtrash', 1);
-            $prefs->setValue('trash_folder', '');
-        } else {
-            if ($prefs->isLocked('trash_folder')) {
-                return false;
-            }
-
-            $updated = $updated | $this->_prefsSpecialFolders($updated, 'trash_folder', 'trash', 'trash_new');
-            if ($updated) {
-                $prefs->setValue('use_vtrash', 0);
-                $prefs->setDirty('trash_folder', true);
-            }
-        }
-
-        return $updated;
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsSourceSelect($updated)
-    {
-        $search_sources = Horde_Util::getFormData('search_sources');
-        if (!is_null($search_sources)) {
-            $GLOBALS['prefs']->setValue('search_sources', $search_sources);
-            unset($_SESSION['imp']['cache']['ac_ajax']);
-            $updated = true;
-        }
-
-        $search_fields_string = Horde_Util::getFormData('search_fields_string');
-        if (!is_null($search_fields_string)) {
-            $GLOBALS['prefs']->setValue('search_fields', $search_fields_string);
-            $updated = true;
-        }
-
-        $add_source = Horde_Util::getFormData('add_source');
-        if (!is_null($add_source)) {
-            $GLOBALS['prefs']->setValue('add_source', $add_source);
-            $updated = true;
-        }
-
-        return $updated;
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsInitialPageSelect()
-    {
-        $initial_page = Horde_Util::getFormData('initial_page');
-        $GLOBALS['prefs']->setValue('initial_page', $initial_page);
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsEncryptSelect()
-    {
-        $default_encrypt = Horde_Util::getFormData('default_encrypt');
-        $GLOBALS['prefs']->setValue('default_encrypt', $default_encrypt);
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsFlagManagement()
-    {
-        $imp_flags = $GLOBALS['injector']->getInstance('IMP_Imap_Flags');
-        $action = Horde_Util::getFormData('flag_action');
-        $data = Horde_Util::getFormData('flag_data');
-
-        if ($action == 'add') {
-            $GLOBALS['notification']->push(sprintf(_("Added flag \"%s\"."), $data), 'horde.success');
-            $imp_flags->addFlag($data);
-            return;
-        }
-
-        $def_color = $GLOBALS['prefs']->getValue('msgflags_color');
-
-        // Don't set updated on these actions. User may want to do more actions.
-        foreach ($imp_flags->getList() as $key => $val) {
-            $md5 = hash('md5', $key);
-
-            switch ($action) {
-            case 'delete':
-                if ($data == ('bg_' . $md5)) {
-                    $imp_flags->deleteFlag($key);
-                    $GLOBALS['notification']->push(sprintf(_("Deleted flag \"%s\"."), $val['l']), 'horde.success');
-                }
-                break;
-
-            default:
-                /* Change labels for user-defined flags. */
-                if ($val['t'] == 'imapp') {
-                    $label = Horde_Util::getFormData('label_' . $md5);
-                    if (strlen($label) && ($label != $val['l'])) {
-                        $imp_flags->updateFlag($key, array('l' => $label));
-                    }
-                }
-
-                /* Change background for all flags. */
-                $bg = strtolower(Horde_Util::getFormData('bg_' . $md5));
-                if ((isset($val['b']) && ($bg != $val['b'])) ||
-                    (!isset($val['b']) && ($bg != $def_color))) {
-                        $imp_flags->updateFlag($key, array('b' => $bg));
-                }
-                break;
-            }
-        }
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsAccountsManagement()
-    {
-        $success = false;
-        $vars = Horde_Variables::getDefaultVariables();
-
-        switch ($vars->accounts_action) {
-        case 'add':
-            if (!$vars->accounts_server ||
-                !$vars->accounts_username) {
-                    $GLOBALS['notification']->push(_("Missing required values."), 'horde.error');
-                } else {
-                    /* Port is not required. */
-                    $port = $vars->accounts_port;
-                    if (!$port) {
-                        $port = ($vars->accounts_type == 'imap') ? 143 : 110;
-                    }
-
-                    /* Label is not required. */
-                    $label = $vars->accounts_label;
-                    if (!strlen($label)) {
-                        $label = $vars->accounts_server . ':' . $port . ' [' . $vars->accounts_type . ']';
-                    }
-
-                    $imp_accounts = $GLOBALS['injector']->getInstance('IMP_Accounts');
-                    $imp_accounts->addAccount(array(
-                        'label' => $label,
-                        'port' => $port,
-                        'secure' => $vars->accounts_secure,
-                        'server' => $vars->accounts_server,
-                        'type' => $vars->accounts_type,
-                        'username' => $vars->accounts_username
-                    ));
-                    $GLOBALS['notification']->push(sprintf(_("Account \"%s\" added."), $vars->accounts_server), 'horde.success');
-
-                    $success = true;
-                }
-            break;
-
-        case 'delete':
-            $imp_accounts = $GLOBALS['injector']->getInstance('IMP_Accounts');
-            $tmp = $imp_accounts->getAccount($vars->accounts_data);
-            if ($imp_accounts->deleteAccount($vars->accounts_data)) {
-                $GLOBALS['notification']->push(sprintf(_("Account \"%s\" deleted."), $tmp['server']), 'horde.success');
-                $success = true;
-            }
-            break;
-        }
-
-        if ($success) {
-            $this->_mailboxesChanged();
-        }
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsPrepareSourceselect()
-    {
-        self::$prefsCache['sourceselect'] = array();
-
-        if (!$GLOBALS['registry']->hasMethod('contacts/sources') ||
-            $GLOBALS['prefs']->isLocked('search_sources')) {
-            return;
-        }
-
-        $readable = $search_fields = $prefSelect = $writeable = $writeSelect = array();
-
-        try {
-            $readable = $GLOBALS['registry']->call('contacts/sources');
-        } catch (Horde_Exception $e) {}
-
-        try {
-            $writeable = $GLOBALS['registry']->call('contacts/sources', array(true));
-        } catch (Horde_Exception $e) {}
-
-        $search = IMP_Compose::getAddressSearchParams();
-
-        if (count($readable) == 1) {
-            // Only one source, no need to display the selection widget
-            $search['sources'] = array_keys($readable);
-        }
-
-        foreach ($search['sources'] as $source) {
-            if (!empty($readable[$source])) {
-                $prefSelect[$source] = $readable[$source];
-            }
-        }
-
-        $readSelect = array_diff(array_keys($readable), $search['sources']);
-
-        if (!$GLOBALS['prefs']->isLocked('add_source')) {
-            foreach ($writeable as $source => $name) {
-                $writeSelect[] = array(
-                    'val' => $source,
-                    'sel' => ($GLOBALS['prefs']->getValue('add_source') == $source),
-                    'name' => $name
-                );
-            }
-        }
-
-        $source_count = 0;
-
-        foreach (array_keys($readable) as $source) {
-            $search_fields[$source_count][] = $source;
-
-            try {
-                foreach ($GLOBALS['registry']->call('contacts/fields', array($source)) as $field) {
-                    if ($field['search']) {
-                        $search_fields[$source_count][] = array($field['name'], $field['label'], isset($search['fields'][$source]) && in_array($field['name'], $search['fields'][$source]));
-                    }
-                }
-            } catch (Horde_Exception $e) {}
-
-            ++$source_count;
-        }
-
-        Horde::addScriptFile('addressbooksprefs.js', 'imp');
-        Horde::addInlineScript(array(
-            'ImpAddressbooksPrefs.fields = ' . Horde_Serialize::serialize($search_fields, Horde_Serialize::JSON, Horde_Nls::getCharset())
-        ));
-        self::$prefsCache['sourceselect'] = array(
-            'prefSelect' => $prefSelect,
-            'readable' => $readable,
-            'readSelect' => $readSelect,
-            'search' => $search,
-            'writeable' => $writeable,
-            'writeSelect' => $writeSelect
-        );
+        return $GLOBALS['injector']->getInstance('IMP_Prefs_Ui')->prefsMenu($ui);
     }
 
     /* Language change callback. */
@@ -975,56 +477,16 @@ class IMP_Application extends Horde_Registry_Application
     public function changeLanguage()
     {
         $this->init();
-        $this->_mailboxesChanged();
+        $this->mailboxesChanged();
         $GLOBALS['imp_search']->initialize(true);
     }
 
-    /* Horde_Prefs_Credentials:: methods. */
-
-    /**
-     * Returns a list of authentication credentials, i.e. server settings that
-     * can be specified by the user on the login screen.
-     *
-     * @return array  A hash with credentials, suited for the preferences
-     *                interface.
-     */
-    public function authCredentials()
-    {
-        $app_name = $GLOBALS['registry']->get('name');
-
-        $servers = IMP_Imap::loadServerConfig();
-        $server_list = array();
-        foreach ($servers as $key => $val) {
-            $server_list[$key] = $val['name'];
-        }
-        reset($server_list);
-
-        $credentials = array(
-            'username' => array(
-                'desc' => sprintf(_("%s for %s"), _("Username"), $app_name),
-                'type' => 'text'
-            ),
-            'password' => array(
-                'desc' => sprintf(_("%s for %s"), _("Password"), $app_name),
-                'type' => 'password'
-            ),
-            'server' => array(
-                'desc' => sprintf(_("%s for %s"), _("Server"), $app_name),
-                'type' => 'enum',
-                'enum' => $server_list,
-                'value' => key($server_list)
-            )
-        );
-
-        return $credentials;
-    }
-
     /* Helper methods. */
 
     /**
      * Run tasks when the mailbox list has changed.
      */
-    protected function _mailboxesChanged()
+    public function mailboxesChanged()
     {
         $GLOBALS['injector']->getInstance('IMP_Folder')->clearFlistCache();
         $GLOBALS['injector']->getInstance('IMP_Imap_Tree')->init();
index 71aa90c..fd02805 100644 (file)
@@ -478,6 +478,7 @@ class IMP_Auth
         /* Suppress menus in options screen and indicate that notifications
          * should use the ajax mode. */
         if ($sess['view'] == 'dimp') {
+            Horde_Core_Prefs_Ui::hideMenu(true);
             $_SESSION['horde_prefs']['nomenu'] = true;
             $_SESSION['horde_notification']['override'] = array(
                 IMP_BASE . '/lib/Notification/Listener/AjaxStatus.php',
index bee7a48..3fa98f1 100644 (file)
@@ -18,7 +18,7 @@ class Horde_Block_imp_tree_folders extends Horde_Block
     protected function _buildTree(&$tree, $indent = 0, $parent = null)
     {
         /* Run filters now */
-        if ($GLOBALS['prefs']->getValue('filter_on_sidebar')) {
+        if ($GLOBALS['prefs']->getValue('filter_on_display')) {
             $imp_filter = new IMP_Filter();
             $imp_filter->filter('INBOX');
         }
index 5e9693e..c7851a0 100644 (file)
@@ -2838,7 +2838,7 @@ class IMP_Compose
      */
     static public function getAddressList($search = '')
     {
-        $sparams = self::getAddressSearchParams();
+        $sparams = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
         try {
             $res = $GLOBALS['registry']->call('contacts/search', array($search, $sparams['sources'], $sparams['fields'], false));
         } catch (Horde_Exception $e) {
@@ -2869,34 +2869,4 @@ class IMP_Compose
         return $search;
     }
 
-    /**
-     * Determines parameters needed to do an address search
-     *
-     * @return array  An array with two keys: 'sources' and 'fields'.
-     */
-    static public function getAddressSearchParams()
-    {
-        $src = explode("\t", $GLOBALS['prefs']->getValue('search_sources'));
-        if ((count($src) == 1) && empty($src[0])) {
-            $src = array();
-        }
-
-        $fields = array();
-        if (($val = $GLOBALS['prefs']->getValue('search_fields'))) {
-            $field_arr = explode("\n", $val);
-            foreach ($field_arr as $field) {
-                $field = trim($field);
-                if (!empty($field)) {
-                    $tmp = explode("\t", $field);
-                    if (count($tmp) > 1) {
-                        $source = array_splice($tmp, 0, 1);
-                        $fields[$source[0]] = $tmp;
-                    }
-                }
-            }
-        }
-
-        return array('sources' => $src, 'fields' => $fields);
-    }
-
 }
index c271a99..4db65f3 100644 (file)
@@ -177,7 +177,7 @@ class IMP_Crypt_Pgp extends Horde_Crypt_Pgp
         }
 
         /* Try retrieving by e-mail only first. */
-        $params = IMP_Compose::getAddressSearchParams();
+        $params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
         try {
             $result = $GLOBALS['registry']->call('contacts/getField', array($address, self::PUBKEY_FIELD, $params['sources'], false, true));
         } catch (Horde_Exception $e) {
@@ -226,7 +226,7 @@ class IMP_Crypt_Pgp extends Horde_Crypt_Pgp
      */
     public function listPublicKeys()
     {
-        $params = IMP_Compose::getAddressSearchParams();
+        $params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
         if (empty($params['sources'])) {
             return array();
         }
@@ -243,7 +243,7 @@ class IMP_Crypt_Pgp extends Horde_Crypt_Pgp
      */
     public function deletePublicKey($email)
     {
-        $params = IMP_Compose::getAddressSearchParams();
+        $params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
         return $GLOBALS['registry']->call('contacts/deleteField', array($email, self::PUBKEY_FIELD, $params['sources']));
     }
 
@@ -637,7 +637,7 @@ class IMP_Crypt_Pgp extends Horde_Crypt_Pgp
         $t->set('import_public_key', $target == 'process_import_public_key');
         $t->set('import_personal_public_key', $target == 'process_import_personal_public_key');
         $t->set('import_personal_private_key', $target == 'process_import_personal_private_key');
-        echo $t->fetch(IMP_TEMPLATES . '/prefs/pgp/import_key.html');
+        echo $t->fetch(IMP_TEMPLATES . '/pgp/import_key.html');
     }
 
     /**
index 19340c2..ae8e79a 100644 (file)
@@ -162,7 +162,7 @@ class IMP_Crypt_Smime extends Horde_Crypt_Smime
         } catch (Horde_Exception_HookNotSet $e) {
         }
 
-        $params = IMP_Compose::getAddressSearchParams();
+        $params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
 
         try {
             $key = $GLOBALS['registry']->call('contacts/getField', array($address, self::PUBKEY_FIELD, $params['sources'], false, true));
@@ -191,7 +191,7 @@ class IMP_Crypt_Smime extends Horde_Crypt_Smime
      */
     public function listPublicKeys()
     {
-        $params = IMP_Compose::getAddressSearchParams();
+        $params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
         if (empty($params['sources'])) {
             return array();
         }
@@ -207,7 +207,7 @@ class IMP_Crypt_Smime extends Horde_Crypt_Smime
      */
     public function deletePublicKey($email)
     {
-        $params = IMP_Compose::getAddressSearchParams();
+        $params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
         $GLOBALS['registry']->call('contacts/deleteField', array($email, self::PUBKEY_FIELD, $params['sources']));
     }
 
@@ -474,7 +474,7 @@ class IMP_Crypt_Smime extends Horde_Crypt_Smime
         $t->set('forminput', Horde_Util::formInput());
         $t->set('import_public_key', $target == 'process_import_public_key');
         $t->set('import_personal_certs', $target == 'process_import_personal_certs');
-        echo $t->fetch(IMP_TEMPLATES . '/prefs/smime/import_key.html');
+        echo $t->fetch(IMP_TEMPLATES . '/smime/import_key.html');
     }
 
     /**
index c327910..fe766db 100644 (file)
@@ -39,6 +39,10 @@ class IMP_Imap_Acl
             throw new Horde_Exception(_("ACL requires an IMAP server."));
         }
 
+        if (empty($_SESSION['imp']['imap']['acl'])) {
+            throw new Horde_Exception(_("ACLs not configured for this server."));
+        }
+
         if (!$GLOBALS['imp_imap']->ob()->queryCapability('ACL')) {
             throw new Horde_Exception(_("IMAP server does not support ACLs."));
         }
index 2f5478e..a44bcc1 100644 (file)
@@ -310,7 +310,7 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html
             return false;
         }
 
-        $params = IMP_Compose::getAddressSearchParams();
+        $params = Horde_Core_Prefs_Utils::getAddressbookSearchParams();
         $headers = $this->_params['contents']->getHeaderOb();
 
         /* Try to get back a result from the search. */
diff --git a/imp/lib/Prefs/Ui.php b/imp/lib/Prefs/Ui.php
new file mode 100644 (file)
index 0000000..6b43e95
--- /dev/null
@@ -0,0 +1,1572 @@
+<?php
+/**
+ * IMP-specific prefs handling.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author  Michael Slusarz <slusarz@horde.org>
+ * @package IMP
+ */
+class IMP_Prefs_Ui
+{
+    /**
+     * Code to run on init when viewing prefs for this application.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    public function prefsInit($ui)
+    {
+        global $conf, $prefs, $registry;
+
+        $pop3 = (isset($_SESSION['imp']['protocol']) && ($_SESSION['imp']['protocol'] == 'pop'));
+
+        switch ($ui->group) {
+        case 'accounts':
+            if (empty($conf['user']['allow_accounts'])) {
+                $ui->suppress[] = 'accountsmanagement';
+            } else {
+                Horde::addScriptFile('accountsprefs.js', 'imp');
+            }
+            break;
+
+        case 'acl':
+            Horde::addScriptFile('acl.js', 'imp');
+            break;
+
+        case 'addressbooks':
+            if (!$prefs->isLocked('sourceselect')) {
+                Horde_Core_Prefs_Ui_Widgets::addressbooksInit($ui);
+            }
+
+            if (!$prefs->isLocked('add_source')) {
+                try {
+                    $sources = array();
+                    foreach ($registry->call('contacts/sources', array(true)) as $source => $name) {
+                        $sources[$source] = $name;
+                    }
+                    $ui->override['add_source'] = $sources;
+                } catch (Horde_Exception $e) {
+                    $ui->suppress[] = 'add_source';
+                }
+            }
+            break;
+
+        case 'compose':
+            if ($prefs->isLocked('default_encrypt')) {
+                $ui->suppress[] = 'encryptselect';
+            }
+            if (empty($conf['compose']['allow_receipts'])) {
+                $ui->suppress[] = 'disposition_request_read';
+            }
+            break;
+
+        case 'delmove':
+            if ($pop3) {
+                $ui->suppress[] = 'move_ham_after_report';
+                $ui->suppress[] = 'use_trash';
+                $ui->suppress[] = 'trashselect';
+                $ui->suppress[] = 'use_vtrash';
+                $ui->suppress[] = 'empty_trash_menu';
+
+                $tmp = $ui->prefs['delete_spam_after_report']['enum'];
+                unset($tmp[2]);
+                $ui->override['delete_spam_after_report'] = $tmp;
+            }
+            break;
+
+        case 'display':
+            /* Set the timezone on this page so the 'time_format' output uses
+             * the configured time zone's time, not the system's time zone. */
+            Horde_Nls::setTimeZone();
+            if ($pop3) {
+                $ui->suppress[] = 'nav_expanded';
+                $ui->suppress[] = 'tree_view';
+                $ui->suppress[] = 'nav_expanded_sidebar';
+            }
+            break;
+
+        case 'filters':
+            if (empty($_SESSION['imp']['filteravail'])) {
+                $ui->suppress[] = 'filter_on_login';
+                $ui->suppress[] = 'filter_on_display';
+                $ui->suppress[] = 'filter_any_mailbox';
+            }
+            if (!$registry->hasMethod('mail/showFilters')) {
+                $ui->suppress[] = 'filters_link';
+            }
+            if (!$registry->hasMethod('mail/showBlacklist')) {
+                $ui->suppress[] = 'filters_blacklist_link';
+            }
+            if (!$registry->hasMethod('mail/showWhitelist')) {
+                $ui->suppress[] = 'filters_whitelist_link';
+            }
+            break;
+
+        case 'flags':
+            Horde::addScriptFile('colorpicker.js', 'horde');
+            Horde::addScriptFile('flagprefs.js', 'imp');
+            break;
+
+        case 'identities':
+            if ($prefs->isLocked('sent_mail_folder')) {
+                $ui->suppress[] = 'sentmailselect';
+            } else {
+                Horde::addScriptFile('folderprefs.js', 'imp');
+            }
+            break;
+
+        case 'logintasks':
+            if ($prefs->isLocked('initial_page')) {
+                $ui->suppress[] = 'initialpageselect';
+            }
+            if ($pop3) {
+                $ui->suppress[] = 'initialpageselect';
+                $ui->suppress[] = 'rename_sentmail_monthly';
+                $ui->suppress[] = 'delete_sentmail_monthly';
+                $ui->suppress[] = 'delete_sentmail_monthly_keep';
+                $ui->suppress[] = 'purge_sentmail';
+                $ui->suppress[] = 'purge_sentmail_interval';
+                $ui->suppress[] = 'purge_sentmail_keep';
+                $ui->suppress[] = 'purge_trash';
+                $ui->suppress[] = 'purge_trash_interval';
+                $ui->suppress[] = 'purge_trash_keep';
+                $ui->suppress[] = 'purge_spam';
+                $ui->suppress[] = 'purge_spam_interval';
+                $ui->suppress[] = 'purge_spam_keep';
+            }
+            break;
+
+        case 'newmail':
+            if ($prefs->isLocked('nav_audio')) {
+                $ui->suppress[] = 'soundselect';
+            }
+            if ($pop3) {
+                $ui->suppress[] = 'nav_poll_all';
+            }
+            break;
+
+        case 'pgp':
+            if ($prefs->getValue('use_pgp')) {
+                Horde::addScriptFile('imp.js', 'imp');
+            } else {
+                $ui->suppress[] = 'use_pgp_text';
+                $ui->suppress[] = 'pgp_attach_pubkey';
+                $ui->suppress[] = 'pgp_scan_body';
+                $ui->suppress[] = 'pgp_verify';
+                $ui->suppress[] = 'pgppublickey';
+                $ui->suppress[] = 'pgpprivatekey';
+            }
+            break;
+
+        case 'server':
+            $code = array();
+
+            if ($prefs->isLocked('drafts_folder')) {
+                $ui->suppress[] = 'draftsselect';
+            } else {
+                $code[] = array('drafts', 'drafts_new', _("Enter the name for your new drafts folder"), _("Create a new drafts folder"));
+            }
+
+            if ($prefs->isLocked('spam_folder')) {
+                $ui->suppress[] = 'spamselect';
+            } else {
+                $code[] = array('spam', 'spam_new', _("Enter the name for your new spam folder"), _("Create a new spam folder"));
+            }
+
+            if (!$prefs->isLocked('trash_folder') &&
+                !$prefs->isLocked('use_vtrash')) {
+                $code[] = array('trash', 'trash_new', _("Enter the name for your new trash folder"), _("Create a new trash folder"));
+            } else {
+                $ui->suppress[] = 'trashselect';
+            }
+
+            if (!empty($code)) {
+                Horde::addScriptFile('folderprefs.js', 'imp');
+                Horde::addInlineScript(array(
+                    'ImpFolderPrefs.folders = ' . Horde_Serialize::serialize($code, Horde_Serialize::JSON, Horde_Nls::getCharset())
+                ));
+            }
+            break;
+
+        case 'smime':
+            $use_smime = false;
+            if ($prefs->getValue('use_smime')) {
+                try {
+                    $GLOBALS['injector']->getInstance('IMP_Crypt_Smime')->checkForOpenSSL();
+                    $use_smime = true;
+                } catch (Horde_Exception $e) {}
+            }
+
+            if ($use_smime) {
+                Horde::addScriptFile('imp.js', 'imp');
+            } else {
+                $ui->suppress[] = 'use_smime_text';
+                $ui->suppress[] = 'smime_verify';
+                $ui->suppress[] = 'smimepublickey';
+                $ui->suppress[] = 'smimeprivatekey';
+            }
+            break;
+
+        case 'stationery':
+            if ($prefs->isLocked('stationery')) {
+                $ui->suppress[]  = 'stationerymanagement';
+            } else {
+                $ui->nobuttons = true;
+            }
+            break;
+
+        case 'viewing':
+            if (empty($conf['maillog']['use_maillog'])) {
+                $ui->suppress[] = 'disposition_send_mdn';
+            }
+            break;
+        }
+
+        /* Hide appropriate prefGroups. */
+        if ($pop3) {
+            $ui->suppressGroups[] = 'server';
+            $ui->suppressGroups[] = 'flags';
+        }
+
+        try {
+            $GLOBALS['injector']->getInstance('IMP_Imap_Acl');
+        } catch (Exception $e) {
+            $ui->suppressGroups[] = 'acl';
+        }
+
+        if (empty($conf['user']['allow_accounts'])) {
+            $ui->suppressGroups[] = 'accounts';
+        }
+
+        $contacts_app = $registry->hasInterface('contacts');
+        if (!$contacts_app || !$registry->hasPermission($contacts_app)) {
+            $ui->suppressGroups[] = 'addressbooks';
+        }
+
+        if (!isset($GLOBALS['conf']['gnupg']['path'])) {
+            $ui->suppressGroups[] = 'pgp';
+        }
+
+        if (!Horde_Util::extensionExists('openssl') ||
+            !isset($conf['openssl']['path'])) {
+            $ui->suppressGroups[] = 'smime';
+        }
+
+        // TODO: For now, disable this group since accounts code has not
+        // yet been fully written.
+        $ui->suppressGroups[] = 'accounts';
+    }
+
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    public function prefsSpecial($ui, $item)
+    {
+        switch ($item) {
+        case 'accountsmanagement':
+            return $this->_accountsManagement($ui);
+
+        case 'aclmanagement':
+            return $this->_aclManagement($ui);
+
+        case 'draftsselect':
+            return $this->_drafts();
+
+        case 'encryptselect':
+            return $this->_encrypt();
+
+        case 'flagmanagement':
+            return $this->_flagManagement();
+
+        case 'initialpageselect':
+            return $this->_initialPage();
+
+        case 'pgpprivatekey':
+            return $this->_pgpPrivateKey($ui);
+
+        case 'pgppublickey':
+            return $this->_pgpPublicKey($ui);
+
+        case 'sentmailselect':
+            return $this->_sentmail();
+
+        case 'smimeprivatekey':
+            return $this->_smimePrivateKey($ui);
+
+        case 'smimepublickey':
+            return $this->_smimePublicKey($ui);
+
+        case 'soundselect':
+            return $this->_sound();
+
+        case 'sourceselect':
+            return Horde_Core_Prefs_Ui_Widgets::addressbooks($ui);
+
+        case 'spamselect':
+            return $this->_spam();
+
+        case 'stationerymanagement':
+            return $this->_stationeryManagement($ui);
+
+        case 'trashselect':
+            return $this->_trash();
+        }
+
+        return '';
+    }
+
+    /**
+     * Special preferences handling on update.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return boolean  True if preference was updated.
+     */
+    public function prefsSpecialUpdate($ui, $item)
+    {
+        global $prefs;
+
+        switch ($item) {
+        case 'accountsmanagement':
+            $this->_updateAccountsManagement($ui);
+            return false;
+
+        case 'aclmanagement':
+            $this->_updateAclManagement($ui);
+            return false;
+
+        case 'draftsselect':
+            return $this->_updateSpecialFolders('drafts_folder', $ui->vars->drafts, $ui->vars->drafts_new, $ui);
+
+        case 'encryptselect':
+            $prefs->setValue('default_encrypt', $ui->vars->default_encrypt);
+            return true;
+
+        case 'flagmanagement':
+            $this->_updateFlagManagement($ui);
+            return false;
+
+        case 'initialpageselect':
+            $prefs->setValue('initial_page', $ui->vars->initial_page);
+            return true;
+
+        case 'pgpprivatekey':
+            $this->_updatePgpPrivateKey($ui);
+            return false;
+
+        case 'pgppublickey':
+            $this->_updatePgpPublicKey($ui);
+            return false;
+
+        case 'sentmailselect':
+            return $this->_updateSentmail($ui);
+
+        case 'smimeprivatekey':
+            $this->_updateSmimePrivateKey($ui);
+            return false;
+
+        case 'smimepublickey':
+            $this->_updateSmimePublicKey($ui);
+            return false;
+
+        case 'soundselect':
+            return $prefs->setValue('nav_audio', $ui->vars->nav_audio);
+
+        case 'sourceselect':
+            if (isset($ui->vars->sources)) {
+                unset($_SESSION['imp']['cache']['ac_ajax']);
+            }
+            return Horde_Core_Prefs_Ui_Widgets::addressbooksUpdate($ui);
+
+        case 'spamselect':
+            return $this->_updateSpecialFolders('spam_folder', $vars->spam, $vars->spam_new, $ui);
+
+        case 'stationerymanagement':
+            return $this->_updateStationeryManagement($ui);
+
+        case 'trashselect':
+            return $this->_updateTrash($ui);
+        }
+
+        return false;
+    }
+
+    /**
+     * Called when preferences are changed.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    public function prefsCallback($ui)
+    {
+        global $prefs;
+
+        /* Always check to make sure we have a valid trash folder if delete to
+         * trash is active. */
+        if (($prefs->isDirty('use_trash') || $prefs->isDirty('trash_folder')) &&
+            $prefs->getValue('use_trash') &&
+            !$prefs->getValue('trash_folder') &&
+            !$prefs->getValue('use_vtrash')) {
+            $GLOBALS['notification']->push(_("You have activated move to Trash but no Trash folder is defined. You will be unable to delete messages until you set a Trash folder in the preferences."), 'horde.warning');
+        }
+
+        switch ($ui->group) {
+        case 'compose':
+            if ($prefs->isDirty('mail_domain')) {
+                $maildomain = preg_replace('/[^-\.a-z0-9]/i', '', $prefs->getValue('mail_domain'));
+                $prefs->setValue('maildomain', $maildomain);
+                if (!empty($maildomain)) {
+                    $_SESSION['imp']['maildomain'] = $maildomain;
+                }
+            }
+
+            if ($prefs->isDirty('compose_popup')) {
+                Horde::addInlineScript(array(
+                    'if (window.parent.frames.horde_menu) window.parent.frames.horde_menu.location.reload();'
+                ));
+            }
+            break;
+
+        case 'delmove':
+            if ($prefs->isDirty('use_vtrash')) {
+                $GLOBALS['imp_search']->initialize(true);
+            }
+            break;
+
+        case 'display':
+            if ($prefs->isDirty('tree_view')) {
+                $GLOBALS['registry']->getApiInstance('imp', 'application')->mailboxesChanged();
+            }
+            break;
+
+        case 'server':
+            if ($prefs->isDirty('use_vinbox')) {
+                $GLOBALS['imp_search']->initialize(true);
+            }
+
+            if ($prefs->isDirty('subscribe')) {
+                $GLOBALS['registry']->getApiInstance('imp', 'application')->mailboxesChanged();
+            }
+            break;
+        }
+    }
+
+    /**
+     * Generate the menu to use on the prefs page.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return Horde_Menu  A Horde_Menu object.
+     */
+    public function prefsMenu($ui)
+    {
+        return IMP::getMenu();
+    }
+
+    /* Accounts management handling. */
+
+    /**
+     * Create code for accounts management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _accountsManagement($ui)
+    {
+        $ui->nobuttons = true;
+
+        Horde::addInlineScript(array(
+            'ImpAccountsPrefs.confirm_delete = ' . Horde_Serialize::serialize(_("Are you sure you want to delete this account?"), Horde_Serialize::JSON, Horde_Nls::getCharset())
+        ));
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        if ($ui->vars->accounts_action == 'new') {
+            $t->set('new', true);
+        } else {
+            $accounts_list = $GLOBALS['injector']->getInstance('IMP_Accounts')->getList();
+            if (!empty($accounts_list)) {
+                $t->set('delete_img', Horde::img('delete.png'));
+
+                $out = array();
+                foreach ($accounts_list as $key => $val) {
+                    $out[] = array(
+                        'id' => $key,
+                        'label' => htmlspecialchars($val['label']),
+                        'port' => htmlspecialchars($val['port']),
+                        'secure' => ($val['secure'] == 'yes'),
+                        'secure_auto' => ($val['secure'] == 'auto'),
+                        'server' => htmlspecialchars($val['server']),
+                        'type' => htmlspecialchars($val['type']),
+                    );
+                }
+                $t->set('accounts', $out);
+            }
+        }
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/accounts.html');
+    }
+
+    /**
+     * Update accounts related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateAccountsManagement($ui)
+    {
+        $success = false;
+
+        switch ($ui->vars->accounts_action) {
+        case 'add':
+            if (!$ui->vars->accounts_server ||
+                !$ui->vars->accounts_username) {
+                    $GLOBALS['notification']->push(_("Missing required values."), 'horde.error');
+                } else {
+                    /* Port is not required. */
+                    $port = $ui->vars->accounts_port;
+                    if (!$port) {
+                        $port = ($ui->vars->accounts_type == 'imap') ? 143 : 110;
+                    }
+
+                    /* Label is not required. */
+                    $label = $ui->vars->accounts_label;
+                    if (!strlen($label)) {
+                        $label = $ui->vars->accounts_server . ':' . $port . ' [' . $ui->vars->accounts_type . ']';
+                    }
+
+                    $imp_accounts = $GLOBALS['injector']->getInstance('IMP_Accounts');
+                    $imp_accounts->addAccount(array(
+                        'label' => $label,
+                        'port' => $port,
+                        'secure' => $ui->vars->accounts_secure,
+                        'server' => $ui->vars->accounts_server,
+                        'type' => $ui->vars->accounts_type,
+                        'username' => $ui->vars->accounts_username
+                    ));
+                    $GLOBALS['notification']->push(sprintf(_("Account \"%s\" added."), $ui->vars->accounts_server), 'horde.success');
+
+                    $success = true;
+                }
+            break;
+
+        case 'delete':
+            $imp_accounts = $GLOBALS['injector']->getInstance('IMP_Accounts');
+            $tmp = $imp_accounts->getAccount($ui->vars->accounts_data);
+            if ($imp_accounts->deleteAccount($ui->vars->accounts_data)) {
+                $GLOBALS['notification']->push(sprintf(_("Account \"%s\" deleted."), $tmp['server']), 'horde.success');
+                $success = true;
+            }
+            break;
+        }
+
+        if ($success) {
+            $GLOBALS['registry']->getApiInstance('imp', 'application')->mailboxesChanged();
+        }
+    }
+
+    /* ACL management. */
+
+    /**
+     * Create code for ACL management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _aclManagement($ui)
+    {
+        $ACL = $GLOBALS['injector']->getInstance('IMP_Imap_Acl');
+        $imp_folder = $GLOBALS['injector']->getInstance('IMP_Folder');
+        $rights = $ACL->getRights();
+
+        $folder = empty($ui->vars->folder)
+            ? 'INBOX'
+            : $ui->vars->folder;
+
+        $curr_acl = $ACL->getACL($folder);
+        $canEdit = $ACL->canEdit($folder, Horde_Auth::getAuth());
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('options', IMP::flistSelect(array('selected' => $folder)));
+        $t->set('current', sprintf(_("Current access to %s"), IMP::displayFolder($folder)));
+        $t->set('folder', $folder);
+        $t->set('noacl', !count($curr_acl));
+        $t->set('maxrule', 1);
+
+        if (!$t->get('noacl')) {
+            $i = 0;
+            $cval = array();
+            $protected = $ACL->getProtected();
+
+            foreach ($curr_acl as $index => $rule) {
+                $entry = array(
+                    'i' => ++$i,
+                    'num_val' => ($i - 1),
+                    'disabled' => in_array($index, $protected) || !$canEdit,
+                    'index' => $index
+                );
+
+                /* Create table of each ACL option for each user granted
+                 * permissions; enabled indicates the right has been given to
+                 * the user */
+                foreach (array_keys($rights) as $val) {
+                    $entry['rule'][] = array(
+                        'enabled' => in_array($val, $rule),
+                        'val' => $val
+                    );
+                 }
+                 $cval[] = $entry;
+             }
+
+             $t->set('curr_acl', $cval);
+             $t->set('maxval', count($curr_acl));
+
+             /* Number of individual ACL options, for table rendering. */
+             $t->set('maxrule', count($rights));
+        }
+
+        $t->set('canedit', $canEdit);
+
+        if (empty($_SESSION['imp']['admin'])) {
+            $t->set('noadmin', true);
+        } else {
+            $current_users = array_keys($curr_acl);
+            $new_user = array();
+
+            foreach ($GLOBALS['registry']->callByPackage('listUsers', 'imp') as $user) {
+                if (in_array($user, $current_users)) {
+                    continue;
+                }
+                $new_user[] = htmlspecialchars($user);
+            }
+            $t->set('new_user', $new_user);
+        }
+
+        $rightsval = array();
+        foreach ($rights as $right => $val) {
+            $rightsval[] = array(
+                'right' => $right,
+                'desc' => $val['desc'],
+                'title' => $val['title']
+            );
+        }
+
+        $t->set('rights', $rightsval);
+        $t->set('width', round(100 / (count($rightsval) + 1)) . '%');
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/acl.html');
+    }
+
+    /**
+     * Update ACL related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateAclManagement($ui)
+    {
+        if ($ui->vars->change_acl_folder) {
+            return;
+        }
+
+        $ACL = $GLOBALS['injector']->getInstance('IMP_Imap_Acl');
+
+        $acl_list = $ui->vars->acl;
+        $new_user = $ui->vars->new_user;
+
+        /* Check to see if $new_user already has an acl on the folder. */
+        if ($new_user && isset($acl_list[$new_user])) {
+            $acl_list[$new_user] = $ui->vars->new_acl;
+        } elseif ($new_user) {
+            try {
+                $ACL->editACL($ui->vars->folder, $new_user, $ui->vars->new_acl);
+                if (count($ui->vars->new_acl)) {
+                    $GLOBALS['notification']->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $new_user, $ui->vars->folder), 'horde.success');
+                } else {
+                    $GLOBALS['notification']->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), $ui->vars->folder, $new_user), 'horde.success');
+                }
+            } catch (Horde_Exception $e) {
+                $GLOBALS['notification']->push($e);
+            }
+        }
+
+        $curr_acl = $ACL->getACL($ui->vars->folder);
+        $protected = $ACL->getProtected();
+
+        foreach ($acl_list as $user => $val) {
+            if ($val) {
+                $val = array_flip($val);
+
+                /* We had to have an empty value submitted to make sure all
+                 * users with acls were sent back, so we can remove those
+                 * without checkmarks. */
+                unset($val['']);
+            } else {
+                $val = array();
+            }
+
+            if (!$user) {
+                $GLOBALS['notification']->push(_("No user specified."), 'horde.error');
+                continue;
+            }
+
+            if (in_array($user, $protected)) {
+                if ($val) {
+                    $GLOBALS['notification']->push(sprintf(_("Rights for user \"%s\" cannot be modified."), $user), 'horde.error');
+                }
+                continue;
+            }
+
+            /* Check to see if ACL changed. */
+            if ((isset($curr_acl[$user])) &&
+                (array_keys($curr_acl[$user]) == array_keys($val))) {
+                continue;
+            }
+
+            try {
+                unset($curr_acl);
+                $ACL->editACL($ui->vars->folder, $user, $val);
+                if (!count($val)) {
+                    $GLOBALS['notification']->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), $ui->vars->folder, $user), 'horde.success');
+                } else {
+                    $GLOBALS['notification']->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $user, $ui->vars->folder), 'horde.success');
+                }
+            } catch (Horde_Exception $e) {
+                $GLOBALS['notification']->push($e);
+            }
+        }
+    }
+
+    /* Drafts selection. */
+
+    /**
+     * Create code for drafts selection.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _drafts()
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('label', Horde::label('drafts', _("Drafts folder:")));
+        $t->set('nofolder', IMP::PREF_NO_FOLDER);
+        $t->set('flist', IMP::flistSelect(array(
+            'filter' => array('INBOX'),
+            'heading' => _("Create a new drafts folder"),
+            'new_folder' => true,
+            'selected' => IMP::folderPref($GLOBALS['prefs']->getValue('drafts_folder'), true)
+        )));
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/drafts.html');
+    }
+
+    /* Message encryption selection. */
+
+    /**
+     * Create code for message encryption selection.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _encrypt()
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+
+        $t->set('label', Horde::label('default_encrypt', _("Your default encryption method for sending messages:")));
+        $t->set('elist', IMP::encryptList());
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/encrypt.html');
+    }
+
+    /* IMAP Flag (keyword) management. */
+
+    /**
+     * Create code for flag management.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _flagManagement()
+    {
+        Horde::addInlineScript(array(
+            'ImpFlagPrefs.new_prompt = ' . Horde_Serialize::serialize(_("Please enter the label for the new flag:"), Horde_Serialize::JSON, Horde_Nls::getCharset()),
+            'ImpFlagPrefs.confirm_delete = ' . Horde_Serialize::serialize(_("Are you sure you want to delete this flag?"), Horde_Serialize::JSON, Horde_Nls::getCharset())
+        ));
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $out = array();
+        $flaglist = $GLOBALS['injector']->getInstance('IMP_Imap_Flags')->getList(array('div' => true, 'fgcolor' => true));
+        foreach ($flaglist as $key => $val) {
+            $hash = hash('md5', $key);
+            $bgid = 'bg_' . $hash;
+            $color = htmlspecialchars($val['b']);
+            $label = htmlspecialchars($val['l']);
+            $bgstyle = 'background-color:' . $color;
+            $tmp = array();
+
+            if ($val['t'] == 'imapp') {
+                $tmp['imapp'] = true;
+                $tmp['label_name'] = 'label_' . $hash;
+                $tmp['label'] = $label;
+                $tmp['icon'] = $bgstyle;
+            } else {
+                $tmp['label'] = Horde::label($bgid, $label);
+                $tmp['icon'] = $val['div'];
+            }
+
+            $tmp['colorstyle'] = $bgstyle . ';color:' . htmlspecialchars($val['f']);
+            $tmp['colorid'] = $bgid;
+            $tmp['color'] = $color;
+
+            $out[] = $tmp;
+        }
+        $t->set('flags', $out);
+
+        $t->set('picker_img', Horde::img('colorpicker.png', _("Color Picker")));
+        $t->set('flag_del', !empty($val['d']));
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/flags.html');
+    }
+
+    /**
+     * Update IMAP flag related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateFlagManagement($ui)
+    {
+        $imp_flags = $GLOBALS['injector']->getInstance('IMP_Imap_Flags');
+
+        if ($ui->vars->action == 'add') {
+            $GLOBALS['notification']->push(sprintf(_("Added flag \"%s\"."), $ui->vars->data), 'horde.success');
+            $imp_flags->addFlag($ui->vars->data);
+            return;
+        }
+
+        $def_color = $GLOBALS['prefs']->getValue('msgflags_color');
+
+        // Don't set updated on these actions. User may want to do more actions.
+        foreach ($imp_flags->getList() as $key => $val) {
+            $md5 = hash('md5', $key);
+
+            switch ($ui->vars->action) {
+            case 'delete':
+                if ($ui->vars->data == ('bg_' . $md5)) {
+                    $imp_flags->deleteFlag($key);
+                    $GLOBALS['notification']->push(sprintf(_("Deleted flag \"%s\"."), $val['l']), 'horde.success');
+                }
+                break;
+
+            default:
+                /* Change labels for user-defined flags. */
+                if ($val['t'] == 'imapp') {
+                    $label = $ui->vars->get('label_' . $md5);
+                    if (strlen($label) && ($label != $val['l'])) {
+                        $imp_flags->updateFlag($key, array('l' => $label));
+                    }
+                }
+
+                /* Change background for all flags. */
+                $bg = strtolower($ui->vars->get('bg_' . $md5));
+                if ((isset($val['b']) && ($bg != $val['b'])) ||
+                    (!isset($val['b']) && ($bg != $def_color))) {
+                    $imp_flags->updateFlag($key, array('b' => $bg));
+                }
+                break;
+            }
+        }
+    }
+
+    /* Initial page selection. */
+
+    /**
+     * Create code for initial page selection.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _initialPage()
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        if (empty($GLOBALS['conf']['user']['allow_folders'])) {
+            $t->set('nofolder', true);
+        } else {
+            $mailbox_selected = $GLOBALS['prefs']->getValue('initial_page');
+            $t->set('folder_sel', $mailbox_selected == 'folders.php');
+            $t->set('flist', IMP::flistSelect(array(
+                'inc_vfolder' => true,
+                'selected' => $mailbox_selected
+            )));
+        }
+
+        $t->set('label', Horde::label('initial_page', _("View or mailbox to display after login:")));
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/initialpage.html');
+    }
+
+    /* PGP Private Key management. */
+
+    /**
+     * Create code for personal PGP key management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _pgpPrivateKey($ui)
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('personalkey-help', Horde_Help::link('imp', 'pgp-overview-personalkey'));
+
+        if (!Horde::isConnectionSecure()) {
+            $t->set('notsecure', true);
+        } else {
+            $pgp_url = Horde::applicationUrl('pgp.php');
+
+            $t->set('has_key', $GLOBALS['prefs']->getValue('pgp_public_key') && $GLOBALS['prefs']->getValue('pgp_private_key'));
+            if ($t->get('has_key')) {
+                $t->set('viewpublic', Horde::link($pgp_url->copy()->add('actionID', 'view_personal_public_key'), _("View Personal Public Key"), null, 'view_key'));
+                $t->set('infopublic', Horde::link($pgp_url->copy()->add('actionID', 'info_personal_public_key'), _("Information on Personal Public Key"), null, 'info_key'));
+                $t->set('sendkey', Horde::link($ui->selfUrl(array('special' => true))->add('send_pgp_key', 1), _("Send Key to Public Keyserver")));
+                $t->set('personalkey-public-help', Horde_Help::link('imp', 'pgp-personalkey-public'));
+
+                $imple = Horde_Ajax_Imple::factory(array('imp', 'PassphraseDialog'), array('type' => 'pgpPersonal'));
+                $imple->attach();
+
+                $imp_pgp = $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp');
+                $passphrase = $imp_pgp->getPassphrase('personal');
+                $t->set('passphrase', empty($passphrase) ? Horde::link('#', _("Enter Passphrase"), null, null, null, null, null, array('id' => $imple->getPassphraseId())) . _("Enter Passphrase") : Horde::link($ui->selfUrl(array('special' => true))->add('unset_pgp_passphrase', 1), _("Unload Passphrase")) . _("Unload Passphrase"));
+
+                $t->set('viewprivate', Horde::link($pgp_url->copy()->add('actionID', 'view_personal_private_key'), _("View Personal Private Key"), null, 'view_key'));
+                $t->set('infoprivate', Horde::link($pgp_url->copy()->add('actionID', 'info_personal_private_key'), _("Information on Personal Private Key"), null, 'info_key'));
+                $t->set('personalkey-private-help', Horde_Help::link('imp', 'pgp-personalkey-private'));
+                $t->set('deletekeypair', addslashes(_("Are you sure you want to delete your keypair? (This is NOT recommended!)")));
+                $t->set('personalkey-delete-help', Horde_Help::link('imp', 'pgp-personalkey-delete'));
+            } else {
+                $imp_identity = Horde_Prefs_Identity::singleton(array('imp', 'imp'));
+                $t->set('fullname', $imp_identity->getFullname());
+                $t->set('personalkey-create-name-help', Horde_Help::link('imp', 'pgp-personalkey-create-name'));
+                $t->set('personalkey-create-comment-help', Horde_Help::link('imp', 'pgp-personalkey-create-comment'));
+                $t->set('fromaddr', $imp_identity->getFromAddress());
+                $t->set('personalkey-create-email-help', Horde_Help::link('imp', 'pgp-personalkey-create-email'));
+                $t->set('personalkey-create-keylength-help', Horde_Help::link('imp', 'pgp-personalkey-create-keylength'));
+                $t->set('personalkey-create-passphrase-help', Horde_Help::link('imp', 'pgp-personalkey-create-passphrase'));
+                $t->set('keygen', addslashes(_("Key generation may take a long time to complete.  Continue with key generation?")));
+
+                if ($_SESSION['imp']['file_upload']) {
+                    $cacheSess = Horde_SessionObjects::singleton();
+                    $t->set('import_url', Horde::popupJs($pgp_url, array('params' => array('actionID' => 'import_personal_public_key', 'reload' => $cacheSess->storeOid($ui->selfUrl()->setRaw(true), false)), 'height' => 275, 'width' => 750, 'urlencode' => true)));
+                }
+
+                $t->set('personalkey-create-actions-help', Horde_Help::link('imp', 'pgp-personalkey-create-actions'));
+            }
+        }
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/pgpprivatekey.html');
+    }
+
+    /**
+     * Update personal PGP related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updatePgpPrivateKey($ui)
+    {
+        if (isset($ui->vars->delete_pgp_privkey)) {
+            $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp')->deletePersonalKeys();
+            $GLOBALS['notification']->push(_("Personal PGP keys deleted successfully."), 'horde.success');
+        } elseif (isset($ui->vars->create_pgp_key)) {
+            /* Check that fields are filled out (except for Comment) and that
+             * the passphrases match. */
+            if (empty($ui->vars->generate_realname) ||
+                empty($ui->vars->generate_email)) {
+                $GLOBALS['notification']->push(_("Name and/or email cannot be empty"), 'horde.error');
+            } elseif (empty($ui->vars->generate_passphrase1) ||
+                      empty($ui->vars->generate_passphrase2)) {
+                $GLOBALS['notification']->push(_("Passphrases cannot be empty"), 'horde.error');
+            } elseif ($ui->vars->generate_passphrase1 !== $ui->vars->generate_passphrase2) {
+               $GLOBALS['notification']->push(_("Passphrases do not match"), 'horde.error');
+            } else {
+                try {
+                    $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp')->generatePersonalKeys($ui->vars->generate_realname, $ui->vars->generate_email, $ui->vars->generate_passphrase1, $ui->vars->_generate_comment, $ui->vars->generate_keylength);
+                    $GLOBALS['notification']->push(_("Personal PGP keypair generated successfully."), 'horde.success');
+                } catch (Exception $e) {
+                    $GLOBALS['notification']->push($e);
+                }
+            }
+        } elseif (isset($ui->vars->send_pgp_key)) {
+            try {
+                $imp_pgp = $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp');
+                $imp_pgp->sendToPublicKeyserver($imp_pgp->getPersonalPublicKey());
+                $GLOBALS['notification']->push(_("Key successfully sent to the public keyserver."), 'horde.success');
+            } catch (Exception $e) {
+                $GLOBALS['notification']->push($e);
+            }
+        } elseif (isset($ui->vars->unset_pgp_passphrase)) {
+            $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp')->unsetPassphrase('personal');
+            $GLOBALS['notification']->push(_("PHP passphrase successfully unloaded."), 'horde.success');
+        }
+    }
+
+    /* PGP Public Key management. */
+
+    /**
+     * Create code for PGP public key management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _pgpPublicKey($ui)
+    {
+        $imp_pgp = $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp');
+
+        /* Get list of Public Keys on keyring. */
+        try {
+            $pubkey_list = $imp_pgp->listPublicKeys();
+        } catch (Horde_Exception $e) {
+            $pubkey_list = array();
+        }
+
+        $pgp_url = Horde::applicationUrl('pgp.php');
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('manage_pubkey-help', Horde_Help::link('imp', 'pgp-manage-pubkey'));
+
+        if (!empty($pubkey_list)) {
+            $plist = array();
+            $self_url = $ui->selfUrl(array('special' => true));
+
+            foreach ($pubkey_list as $val) {
+                $plist[] = array(
+                    'name' => $val['name'],
+                    'email' => $val['email'],
+                    'view' => Horde::link($pgp_url->copy()->add(array('actionID' => 'view_public_key', 'email' => $val['email'])), sprintf(_("View %s Public Key"), $val['name']), null, 'view_key'),
+                    'info' => Horde::link($pgp_url->copy()->add(array('actionID' => 'info_public_key', 'email' => $val['email'])), sprintf(_("Information on %s Public Key"), $val['name']), null, 'info_key'),
+                    'delete' => Horde::link($self_url->copy()->add(array('delete_pgp_pubkey' => 1, 'email' => $val['email'])), sprintf(_("Delete %s Public Key"), $val['name']), null, null, "confirm('" . addslashes(_("Are you sure you want to delete this public key?")) . "')")
+                );
+            }
+            $t->set('pubkey_list', $plist);
+        }
+
+        if ($_SESSION['imp']['file_upload']) {
+            $t->set('no_source', !$GLOBALS['prefs']->getValue('add_source'));
+            if (!$t->get('no_source')) {
+                $cacheSess = Horde_SessionObjects::singleton();
+                $t->set('import_url', Horde::popupJs($pgp_url, array('params' => array('actionID' => 'import_public_key', 'reload' => $cacheSess->storeOid($ui->selfUrl()->setRaw(true), false)), 'height' => 275, 'width' => 750, 'urlencode' => true)));
+                $t->set('import_pubkey-help', Horde_Help::link('imp', 'pgp-import-pubkey'));
+            }
+        }
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/pgppublickey.html');
+    }
+
+    /**
+     * Update PGP public key related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updatePgpPublicKey($ui)
+    {
+        if (isset($ui->vars->delete_pgp_pubkey)) {
+            try {
+                $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp')->deletePublicKey($ui->vars->email);
+                $GLOBALS['notification']->push(sprintf(_("PGP Public Key for \"%s\" was successfully deleted."), $ui->vars->email), 'horde.success');
+            } catch (Horde_Exception $e) {
+                $GLOBALS['notification']->push($e);
+            }
+        }
+    }
+
+    /* Sentmail selection. */
+
+    /**
+     * Create code for sentmail selection.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _sentmail()
+    {
+        Horde::addInlineScript(array(
+            'ImpFolderPrefs.folders = ' . Horde_Serialize::serialize(array('sent_mail_folder', 'sent_mail_new', _("Enter the name for your new sent-mail folder"), _("Create a new sent-mail folder")), Horde_Serialize::JSON, Horde_Nls::getCharset())
+        ));
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('label', Horde::label('sent_mail_folder', _("Sent mail folder:")));
+        $t->set('flist', IMP::flistSelect(array(
+            'filter' => array('INBOX'),
+            'heading' => _("Create a new sent mail folder")
+        )));
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/sentmail.html');
+    }
+
+    /**
+     * Update sentmail related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return boolean  True if preferences were updated.
+     */
+    protected function _updateSentmail($ui)
+    {
+        if (!$GLOBALS['conf']['user']['allow_folders'] ||
+            $GLOBALS['prefs']->isLocked('sent_mail_folder')) {
+            return false;
+        }
+
+        $sent_mail_folder = $ui->vars->sent_mail_folder;
+        $sent_mail_new = Horde_String::convertCharset($ui->vars->sent_mail_new, Horde_Nls::getCharset(), 'UTF7-IMAP');
+        $sent_mail_default = $GLOBALS['prefs']->getValue('sent_mail_folder');
+
+        if (empty($sent_mail_folder) && !empty($sent_mail_new)) {
+            $sent_mail_folder = $GLOBALS['imp_imap']->appendNamespace($sent_mail_new);
+        } elseif (($sent_mail_folder == '-1') && !empty($sent_mail_default)) {
+            $sent_mail_folder = $GLOBALS['imp_imap']->appendNamespace($sent_mail_default);
+        }
+
+        if (!empty($sent_mail_folder)) {
+            $imp_folder = $GLOBALS['injector']->getInstance('IMP_Folder');
+            if (!$imp_folder->exists($sent_mail_folder)) {
+                $imp_folder->create($sent_mail_folder, $GLOBALS['prefs']->getValue('subscribe'));
+            }
+        }
+
+        $imp_identity = Horde_Prefs_Identity::singleton(array('imp', 'imp'));
+        $imp_identity->setValue('sent_mail_folder', IMP::folderPref($sent_mail_folder, false));
+
+        return true;
+    }
+
+    /* Personal S/MIME certificate management. */
+
+    /**
+     * Create code for personal S/MIME certificate management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _smimePrivateKey($ui)
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('personalkey-help', Horde_Help::link('imp', 'smime-overview-personalkey'));
+
+        if (!Horde::isConnectionSecure()) {
+            $t->set('notsecure', true);
+        } else {
+            $smime_url = Horde::applicationUrl('smime.php');
+
+            $t->set('has_key', $GLOBALS['prefs']->getValue('smime_public_key') && $GLOBALS['prefs']->getValue('smime_private_key'));
+            if ($t->get('has_key')) {
+                $t->set('viewpublic', Horde::link($smime_url->copy()->add('actionID', 'view_personal_public_key'), _("View Personal Public Certificate"), null, 'view_key'));
+                $t->set('infopublic', Horde::link($smime_url->copy()->add('actionID', 'info_personal_public_key'), _("Information on Personal Public Certificate"), null, 'info_key'));
+
+                $imple = Horde_Ajax_Imple::factory(array('imp', 'PassphraseDialog'), array('type' => 'smimePersonal'));
+                $imple->attach();
+
+                $imp_smime = $GLOBALS['injector']->getInstance('IMP_Crypt_Smime');
+                $passphrase = $imp_smime->getPassphrase();
+                $t->set('passphrase', empty($passphrase) ? Horde::link('#', _("Enter Passphrase"), null, null, null, null, null, array('id' => $imple->getPassphraseId())) . _("Enter Passphrase") : Horde::link($ui->selfUrl(array('special' => true))->add('unset_smime_passphrase', 1), _("Unload Passphrase")) . _("Unload Passphrase"));
+
+                $t->set('viewprivate', Horde::link($smime_url->copy()->add('actionID', 'view_personal_private_key'), _("View Personal Private Key"), null, 'view_key'));
+                $t->set('deletekeypair', addslashes(_("Are you sure you want to delete your keypair? (This is NOT recommended!)")));
+                $t->set('personalkey-delete-help', Horde_Help::link('imp', 'smime-delete-personal-certs'));
+            } elseif ($_SESSION['imp']['file_upload']) {
+                $cacheSess = Horde_SessionObjects::singleton();
+                $t->set('import_url', Horde::popupJs($smime_url, array('params' => array('actionID' => 'import_personal_public_key', 'reload' => $cacheSess->storeOid($ui->selfUrl()->setRaw(true), false)), 'height' => 275, 'width' => 750, 'urlencode' => true)));
+                $t->set('import-cert-help', Horde_Help::link('imp', 'smime-import-personal-certs'));
+            }
+        }
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/smimeprivatekey.html');
+    }
+
+    /**
+     * Update personal S/MIME certificate related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateSmimePrivateKey($ui)
+    {
+        if (isset($ui->vars->delete_smime_personal)) {
+            $GLOBALS['injector']->getInstance('IMP_Crypt_Smime')->deletePersonalKeys();
+            $GLOBALS['notification']->push(_("Personal S/MIME keys deleted successfully."), 'horde.success');
+        } elseif (isset($ui->vars->unset_smime_passphrase)) {
+            $GLOBALS['injector']->getInstance('IMP_Crypt_Smime')->unsetPassphrase();
+            $GLOBALS['notification']->push(_("S/MIME passphrase successfully unloaded."), 'horde.success');
+        }
+    }
+
+    /* S/MIME public certificate management. */
+
+    /**
+     * Create code for S/MIME public certificate management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _smimePublicKey($ui)
+    {
+        $imp_smime = $GLOBALS['injector']->getInstance('IMP_Crypt_Smime');
+
+        /* Get list of Public Keys on keyring. */
+        try {
+            $pubkey_list = $imp_smime->listPublicKeys();
+        } catch (Horde_Exception $e) {
+            $pubkey_list = array();
+        }
+
+        $smime_url = Horde::applicationUrl('smime.php');
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('manage_pubkey-help', Horde_Help::link('imp', 'smime-manage-pubkey'));
+
+        if (!empty($pubkey_list)) {
+            $plist = array();
+            $self_url = $ui->selfUrl(array('special' => true));
+
+            foreach ($pubkey_list as $val) {
+                $plist[] = array(
+                    'name' => $val['name'],
+                    'email' => $val['email'],
+                    'view' => Horde::link($smime_url->copy()->add(array('actionID' => 'view_public_key', 'email' => $val['email'])), sprintf(_("View %s Public Key"), $val['name']), null, 'view_key'),
+                    'info' => Horde::link($smime_url->copy()->add(array('actionID' => 'info_public_key', 'email' => $val['email'])), sprintf(_("Information on %s Public Key"), $val['name']), null, 'info_key'),
+                    'delete' => Horde::link($self_url->copy()->add(array('delete_smime_pubkey' => 1, 'email' => $val['email'])), sprintf(_("Delete %s Public Key"), $val['name']), null, null, "confirm('" . addslashes(_("Are you sure you want to delete this public key?")) . "')")
+                );
+            }
+            $t->set('pubkey_list', $plist);
+        }
+
+        if ($_SESSION['imp']['file_upload']) {
+            $t->set('no_source', !$GLOBALS['prefs']->getValue('add_source'));
+            if (!$t->get('no_source')) {
+                $cacheSess = Horde_SessionObjects::singleton();
+                $t->set('import_url', Horde::popupJs($smime_url, array('params' => array('actionID' => 'import_public_key', 'reload' => $cacheSess->storeOid($ui->selfUrl()->setRaw(true), false)), 'height' => 275, 'width' => 750, 'urlencode' => true)));
+                $t->set('import_pubkey-help', Horde_Help::link('imp', 'smime-import-pubkey'));
+            }
+        }
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/smimepublickey.html');
+    }
+
+    /**
+     * Update S/MIME public key related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateSmimePublicKey($ui)
+    {
+        if (isset($ui->vars->delete_smime_pubkey)) {
+            try {
+                $GLOBALS['injector']->getInstance('IMP_Crypt_Smime')->deletePublicKey($ui->vars->email);
+                $GLOBALS['notification']->push(sprintf(_("S/MIME Public Key for \"%s\" was successfully deleted."), $ui->vars->email), 'horde.success');
+            } catch (Horde_Exception $e) {
+                $GLOBALS['notification']->push($e);
+            }
+        }
+    }
+
+    /* Sound selection. */
+
+    /**
+     * Create code for sound selection.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _sound()
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $nav_audio = $GLOBALS['prefs']->getValue('nav_audio');
+
+        $t->set('nav_audio', $nav_audio);
+
+        $sounds = array();
+        foreach (Horde_Themes::soundList() as $key => $val) {
+            $sounds[] = array(
+                'c' => ($nav_audio == $key),
+                'l' => htmlspecialchars($key),
+                's' => htmlspecialchars($val->uri),
+                'v' => htmlspecialchars($key)
+            );
+        }
+        $t->set('sounds', $sounds);
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/sound.html');
+    }
+
+    /* Spam selection. */
+
+    /**
+     * Create code for spam selection.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _spam()
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $t->set('label', Horde::label('spam', _("Spam folder:")));
+        $t->set('nofolder', IMP::PREF_NO_FOLDER);
+        $t->set('flist', IMP::flistSelect(array(
+            'filter' => array('INBOX'),
+            'heading' => _("Create a new Spam folder"),
+            'new_folder' => true,
+            'selected' => IMP::folderPref($GLOBALS['prefs']->getValue('spam_folder'), true)
+        )));
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/spam.html');
+    }
+
+    /* Stationery management. */
+
+    /**
+     * Create code for stationery management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _stationeryManagement($ui)
+    {
+        $ob = $this->_parseStationeryVars($ui);
+
+        if ($ob->stationery['t'] == 'html') {
+            $GLOBALS['injector']->getInstance('Horde_Editor')->getEditor('Ckeditor', array('id' => 'content'));
+        }
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $slist = array();
+        foreach ($ob->stationery_list as $key => $choice) {
+            $slist[] = array(
+                'selected' => ($ob->selected === $key),
+                'text' => $choice['n'] . ' ' . ($choice['t'] == 'html' ? _("(HTML)") : _("(Plain Text)")),
+                'val' => $key
+            );
+        }
+        $t->set('slist', $slist);
+
+        $t->set('selected', strlen($ob->selected));
+        $t->set('last_type', $ob->stationery['t']);
+        $t->set('name_label', Horde::label('name', _("Stationery name:")));
+        $t->set('name', $ob->stationery['n']);
+        $t->set('type_label', Horde::label('name', _("Stationery type:")));
+        $t->set('plain', $ob->stationery['t'] == 'plain');
+        $t->set('html', $ob->stationery['t'] == 'html');
+        $t->set('content_label', Horde::label('content', _("Stationery:")));
+        $t->set('content', $ob->stationery['c']);
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/stationery.html');
+    }
+
+    /**
+     * Update stationery related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    protected function _updateStationeryManagement($ui)
+    {
+        $updated = false;
+
+        if ($ui->vars->delete) {
+            /* Delete stationery. */
+            $ob = $this->_parseStationeryVars($ui);
+
+            if (isset($ob->stationery_list[$ob->selected])) {
+                $updated = sprintf(_("The stationery \"%s\" has been deleted."), $ob->stationery_list[$ob->selected]['n']);
+                unset($ob->stationery_list[$ob->selected]);
+            }
+        } elseif ($ui->vars->save) {
+            /* Saving stationery. */
+            $ob = $this->_parseStationeryVars($ui);
+
+            if (strlen($ob->selected)) {
+                $ob->stationery_list[$ob->selected] = $ob->stationery;
+                $updated = sprintf(_("The stationery \"%s\" has been updated."), $ob->stationery['n']);
+            } else {
+                $ob->stationery_list[] = $ob->stationery;
+                $updated = sprintf(_("The stationery \"%s\" has been added."), $ob->stationery['n']);
+            }
+        }
+
+        if ($updated) {
+            $GLOBALS['prefs']->setValue('stationery', serialize(Horde_String::convertCharset(array_values($ob->stationery_list), Horde_Nls::getCharset(), $GLOBALS['prefs']->getCharset())), false);
+            $GLOBALS['notification']->push($updated, 'horde.success');
+        }
+    }
+
+    /**
+     * Parse the variables for the stationery management screen.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return object  Object with the following properties:
+     * <pre>
+     * 'selected' - (integer) The currently selected value.
+     * 'stationery' - (array) The current stationery entry.
+     * 'stationery_list' - (array) The list of all stationery values.
+     * </pre>
+     */
+    protected function _parseStationeryVars($ui)
+    {
+        $ob = new stdClass;
+
+        $ob->selected = strlen($ui->vars->stationery)
+            ? intval($ui->vars->stationery)
+            : null;
+
+        $stationery_list = @unserialize($GLOBALS['prefs']->getValue('stationery', false));
+        $ob->stationery_list = is_array($stationery_list)
+            ? Horde_String::convertCharset($stationery_list, $GLOBALS['prefs']->getCharset())
+            : array();
+
+        $content = strval($ui->vars->content);
+        $type = isset($ui->vars->type)
+            ? $ui->vars->type
+            : 'plain';
+
+        if ($ui->vars->last_type != $type) {
+            $content = ($type == 'plain')
+                ? Horde_Text_Filter::filter($content, 'Html2text', array('charset' => Horde_Nls::getCharset()))
+                : nl2br(htmlspecialchars(htmlspecialchars($content)));
+        }
+
+        $ob->stationery = array(
+            'c' => $content,
+            'n' => strval($ui->vars->name),
+            't' => $type
+        );
+
+        return $ob;
+    }
+
+    /* Trash selection. */
+
+    /**
+     * Create code for trash selection.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _trash()
+    {
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        $use_vtrash = $GLOBALS['prefs']->getValue('use_vtrash');
+
+        $t->set('label', Horde::label('trash', _("Trash folder:")));
+        $t->set('nofolder', IMP::PREF_NO_FOLDER);
+        $t->set('vtrash', IMP::PREF_VTRASH);
+        $t->set('vtrash_select', $use_vtrash);
+        $t->set('flist', IMP::flistSelect(array(
+            'filter' => array('INBOX'),
+            'heading' => _("Create a new trash folder"),
+            'new_folder' => true,
+            'selected' => ($use_vtrash ? null : IMP::folderPref($GLOBALS['prefs']->getValue('trash_folder'), true))
+        )));
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/trash.html');
+    }
+
+    /**
+     * Update trash related preferences.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return boolean  True if preferences were updated.
+     */
+    protected function _updateTrash($ui)
+    {
+        global $prefs;
+
+        if ($ui->vars->trash == IMP::PREF_VTRASH) {
+            if ($prefs->isLocked('use_vtrash')) {
+                return false;
+            }
+
+            $prefs->setValue('use_vtrash', 1);
+            $prefs->setValue('trash_folder', '');
+        } else {
+            if ($prefs->isLocked('trash_folder')) {
+                return false;
+            }
+
+            if ($this->_updateSpecialFolders('trash_folder', $ui->vars->trash, $ui->vars->trash_new, $ui)) {
+                $prefs->setValue('use_vtrash', 0);
+                $prefs->setDirty('trash_folder', true);
+                return true;
+            }
+        }
+    }
+
+    /* Utility functions. */
+
+    /**
+     * Update special folder preferences.
+     *
+     * @param string $pref             The pref name to update.
+     * @param string $folder           The old name.
+     * @param string $new              The new name.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return boolean  True if preferences were updated.
+     */
+    protected function _updateSpecialFolders($pref, $folder, $new, $ui)
+    {
+        global $prefs;
+
+        if (!$GLOBALS['conf']['user']['allow_folders'] ||
+            (strlen($folder) == 0) ||
+            $prefs->isLocked($pref)) {
+            return false;
+        }
+
+        $new = Horde_String::convertCharset($new, Horde_Nls::getCharset(), 'UTF7-IMAP');
+
+        if ($folder == IMP::PREF_NO_FOLDER) {
+            $prefs->setValue($pref, '');
+        } else {
+            if (empty($folder) && !empty($new)) {
+                $folder = $GLOBALS['imp_imap']->appendNamespace($new);
+                if (!$GLOBALS['injector']->getInstance('IMP_Folder')->create($folder, $GLOBALS['prefs']->getValue('subscribe'))) {
+                    $folder = null;
+                }
+            }
+
+            if (!empty($folder)) {
+                $prefs->setValue($pref, IMP::folderPref($folder, false));
+                return true;
+            }
+        }
+    }
+
+}
index c1f8cda..1402b5e 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * PGP preferences handling.
+ * PGP utilities.
  *
  * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
  *
 require_once dirname(__FILE__) . '/lib/Application.php';
 Horde_Registry::appInit('imp');
 
-$imp_pgp = $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp');
+$imp_pgp = $injector->getInstance('IMP_Crypt_Pgp');
 $secure_check = Horde::isConnectionSecure();
+$vars = Horde_Variables::getDefaultVariables();
 
 /* Run through the action handlers */
-$actionID = Horde_Util::getFormData('actionID');
-switch ($actionID) {
-case 'generate_key':
-    /* Check that fields are filled out (except for Comment) and that the
-       passphrases match. */
-    $realname = Horde_Util::getFormData('generate_realname');
-    $email = Horde_Util::getFormData('generate_email');
-    $comment = Horde_Util::getFormData('generate_comment');
-    $keylength = Horde_Util::getFormData('generate_keylength');
-    $passphrase1 = Horde_Util::getFormData('generate_passphrase1');
-    $passphrase2 = Horde_Util::getFormData('generate_passphrase2');
-
-    if (empty($realname) || empty($email)) {
-        $notification->push(_("Name and/or email cannot be empty"), 'horde.error');
-    } elseif (empty($passphrase1) || empty($passphrase2)) {
-        $notification->push(_("Passphrases cannot be empty"), 'horde.error');
-    } elseif ($passphrase1 !== $passphrase2) {
-        $notification->push(_("Passphrases do not match"), 'horde.error');
-    } else {
-        try {
-            $imp_pgp->generatePersonalKeys($realname, $email, $passphrase1, $comment, $keylength);
-            $notification->push(_("Personal PGP keypair generated successfully."), 'horde.success');
-        } catch (Horde_Exception $e) {
-            $notification->push($e);
-        }
-    }
-    break;
-
-case 'delete_key':
-    $imp_pgp->deletePersonalKeys();
-    $notification->push(_("Personal PGP keys deleted successfully."), 'horde.success');
-    break;
-
+switch ($vars->actionID) {
 case 'import_public_key':
-    $imp_pgp->importKeyDialog('process_import_public_key', Horde_Util::getFormData('reload'));
-    exit;
+    $imp_pgp->importKeyDialog('process_import_public_key', $vars->reload);
+    break;
 
 case 'process_import_public_key':
     try {
-        $publicKey = $imp_pgp->getImportKey(Horde_Util::getFormData('import_key'));
+        $publicKey = $imp_pgp->getImportKey($vars->import_key);
         /* Add the public key to the storage system. */
         $key_info = $imp_pgp->addPublicKey($publicKey);
         foreach ($key_info['signature'] as $sig) {
             $notification->push(sprintf(_("PGP Public Key for \"%s (%s)\" was successfully added."), $sig['name'], $sig['email']), 'horde.success');
         }
-        $imp_pgp->reloadWindow(Horde_Util::getFormData('reload'));
+        $imp_pgp->reloadWindow($vars->reload);
     } catch (Horde_Browser_Exception $e) {
         $notification->push(_("No PGP public key imported."), 'horde.error');
         throw new Horde_Exception_Prior($e);
     } catch (Horde_Exception $e) {
         $notification->push($e);
-        $actionID = 'import_public_key';
-        $imp_pgp->importKeyDialog('process_import_public_key', Horde_Util::getFormData('reload'));
+        $vars->actionID = 'import_public_key';
+        $imp_pgp->importKeyDialog('process_import_public_key', $vars->reload);
     }
-    exit;
+    break;
 
 case 'import_personal_public_key':
-    $imp_pgp->importKeyDialog('process_import_personal_public_key', Horde_Util::getFormData('reload'));
-    exit;
+    $imp_pgp->importKeyDialog('process_import_personal_public_key', $vars->reload);
+    break;
 
 case 'process_import_personal_public_key':
-    $actionID = 'import_personal_public_key';
+    $vars->actionID = 'import_personal_public_key';
     /* Check the public key. */
     try {
-        $publicKey = $imp_pgp->getImportKey(Horde_Util::getFormData('import_key'));
+        $publicKey = $imp_pgp->getImportKey($vars->import_key);
         if (($key_info = $imp_pgp->pgpPacketInformation($publicKey)) &&
             isset($key_info['public_key'])) {
             if (isset($key_info['secret_key'])) {
                 /* Key contains private key too, don't allow to add this
                  * as public key. */
                 $notification->push(_("Imported key contains your PGP private key. Only add your public key in the first step!"), 'horde.error');
-                $imp_pgp->importKeyDialog('process_import_personal_public_key', Horde_Util::getFormData('reload'));
+                $imp_pgp->importKeyDialog('process_import_personal_public_key', $vars->reload);
             } else {
                 /* Success in importing public key - Move on to private
                  * key now. */
                 $imp_pgp->addPersonalPublicKey($publicKey);
                 $notification->push(_("PGP public key successfully added."), 'horde.success');
-                $actionID = 'import_personal_private_key';
-                $imp_pgp->importKeyDialog('process_import_personal_private_key', Horde_Util::getFormData('reload'));
+                $vars->actionID = 'import_personal_private_key';
+                $imp_pgp->importKeyDialog('process_import_personal_private_key', $vars->reload);
             }
         } else {
             /* Invalid public key imported - Redo public key import
              * screen. */
             $notification->push(_("Invalid personal PGP public key."), 'horde.error');
-            $imp_pgp->importKeyDialog('process_import_personal_public_key', Horde_Util::getFormData('reload'));
+            $imp_pgp->importKeyDialog('process_import_personal_public_key', $vars->reload);
         }
     } catch (Horde_Browser_Exception $e) {
         $notification->push(_("No personal PGP public key imported."), 'horde.error');
         throw new Horde_Exception_Prior($e);
     } catch (Horde_Exception $e) {
         $notification->push($e);
-        $imp_pgp->importKeyDialog('process_import_personal_public_key', Horde_Util::getFormData('reload'));
+        $imp_pgp->importKeyDialog('process_import_personal_public_key', $vars->reload);
     }
-    exit;
+    break;
 
 case 'process_import_personal_private_key':
-    $actionID = 'import_personal_private_key';
+    $vars->actionID = 'import_personal_private_key';
     /* Check the private key. */
     try {
-        $privateKey = $imp_pgp->getImportKey(Horde_Util::getFormData('import_key'));
+        $privateKey = $imp_pgp->getImportKey($vars->import_key);
         if (($key_info = $imp_pgp->pgpPacketInformation($privateKey)) &&
             isset($key_info['secret_key'])) {
             /* Personal public and private keys have been imported
              * successfully - close the import popup window. */
             $imp_pgp->addPersonalPrivateKey($privateKey);
             $notification->push(_("PGP private key successfully added."), 'horde.success');
-            $imp_pgp->reloadWindow(Horde_Util::getFormData('reload'));
+            $imp_pgp->reloadWindow($vars->reload);
         } else {
             /* Invalid private key imported - Redo private key import
              * screen. */
             $notification->push(_("Invalid personal PGP private key."), 'horde.error');
-            $imp_pgp->importKeyDialog('process_import_personal_private_key', Horde_Util::getFormData('reload'));
+            $imp_pgp->importKeyDialog('process_import_personal_private_key', $vars->reload);
         }
     } catch (Horde_Browser_Exception $e) {
         $notification->push(_("No personal PGP private key imported."), 'horde.error');
         throw new Horde_Exception_Prior($e);
     } catch (Horde_Exception $e) {
         $notification->push($e);
-        $imp_pgp->importKeyDialog('process_import_personal_private_key', Horde_Util::getFormData('reload'));
+        $imp_pgp->importKeyDialog('process_import_personal_private_key', $vars->reload);
     }
-    exit;
+    break;
 
 case 'view_public_key':
 case 'info_public_key':
     try {
-        $key = $imp_pgp->getPublicKey(Horde_Util::getFormData('email'), array('noserver' => true));
+        $key = $imp_pgp->getPublicKey($vars->email, array('noserver' => true));
     } catch (Horde_Exception $e) {
         $key = $e->getMessage();
     }
-    if ($actionID == 'view_public_key') {
+    if ($vars->actionID == 'view_public_key') {
         $imp_pgp->textWindowOutput('PGP Public Key', $key);
     } else {
         $imp_pgp->printKeyInfo($key);
     }
-    exit;
+    break;
 
 case 'view_personal_public_key':
     $imp_pgp->textWindowOutput('PGP Personal Public Key', $imp_pgp->getPersonalPublicKey());
-    exit;
+    break;
 
 case 'info_personal_public_key':
     $imp_pgp->printKeyInfo($imp_pgp->getPersonalPublicKey());
-    exit;
+    break;
 
 case 'view_personal_private_key':
     $imp_pgp->textWindowOutput('PGP Personal Private Key', $imp_pgp->getPersonalPrivateKey());
-    exit;
+    break;
 
 case 'info_personal_private_key':
     $imp_pgp->printKeyInfo($imp_pgp->getPersonalPrivateKey());
-    exit;
-
-case 'delete_public_key':
-    try {
-        $imp_pgp->deletePublicKey(Horde_Util::getFormData('email'));
-        $notification->push(sprintf(_("PGP Public Key for \"%s\" was successfully deleted."), Horde_Util::getFormData('email')), 'horde.success');
-    } catch (Horde_Exception $e) {
-        $notification->push($e);
-    }
-    break;
-
-case 'save_options':
-    $prefs->setValue('use_pgp', Horde_Util::getFormData('use_pgp') ? 1 : 0);
-    $prefs->setValue('pgp_attach_pubkey', Horde_Util::getFormData('pgp_attach_pubkey') ? 1 : 0);
-    $prefs->setValue('pgp_scan_body', Horde_Util::getFormData('pgp_scan_body') ? 1 : 0);
-    $prefs->setValue('pgp_verify', Horde_Util::getFormData('pgp_verify') ? 1 : 0);
-    $notification->push(_("Preferences successfully updated."), 'horde.success');
     break;
 
 case 'save_attachment_public_key':
     /* Retrieve the key from the message. */
-    $contents = IMP_Contents::singleton(Horde_Util::getFormData('uid') . IMP::IDX_SEP . Horde_Util::getFormData('mailbox'));
-    $mime_part = $contents->getMIMEPart(Horde_Util::getFormData('mime_id'));
+    $contents = IMP_Contents::singleton($vars->uid . IMP::IDX_SEP . $vars->mailbox);
+    $mime_part = $contents->getMIMEPart($vars->mime_id);
     if (empty($mime_part)) {
         throw new IMP_Exception('Cannot retrieve public key from message.');
     }
@@ -202,131 +154,5 @@ case 'save_attachment_public_key':
     } catch (Horde_Exception $e) {
         $notification->push($e, $key_info->getCode());
     }
-    exit;
-
-case 'unset_passphrase':
-    $imp_pgp->unsetPassphrase('personal');
-    $notification->push(_("Passphrase successfully unloaded."), 'horde.success');
-    break;
-
-case 'send_public_key':
-    try {
-        $imp_pgp->sendToPublicKeyserver($imp_pgp->getPersonalPublicKey());
-        $notification->push(_("Key successfully sent to the public keyserver."), 'horde.success');
-    } catch (Horde_Exception $e) {
-        $notification->push($e);
-    }
     break;
 }
-
-$selfURL = Horde::applicationUrl('pgp.php');
-
-/* Get list of Public Keys on keyring. */
-try {
-    $pubkey_list = $imp_pgp->listPublicKeys();
-} catch (Horde_Exception $e) {
-    $pubkey_list = array();
-    $notification->push($e);
-}
-
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_Ui::generateHeader('imp', null, 'pgp', $chunk);
-
-/* If PGP preference not active, do NOT show PGP Admin screen. */
-$t = $injector->createInstance('Horde_Template');
-$t->setOption('gettext', true);
-if ($prefs->getValue('use_pgp')) {
-    Horde::addScriptFile('imp.js', 'imp');
-    $t->set('pgpactive', true);
-    $t->set('overview-help', Horde_Help::link('imp', 'pgp-overview'));
-    $t->set('attach_pubkey_notlocked', !$prefs->isLocked('pgp_attach_pubkey'));
-    if ($t->get('attach_pubkey_notlocked')) {
-        $t->set('attach_pubkey', $prefs->getValue('pgp_attach_pubkey'));
-        $t->set('attach_pubkey-help', Horde_Help::link('imp', 'pgp-option-attach-pubkey'));
-    }
-    $t->set('scan_body_notlocked', !$prefs->isLocked('pgp_scan_body'));
-    if ($t->get('scan_body_notlocked')) {
-        $t->set('scan_body', $prefs->getValue('pgp_scan_body'));
-        $t->set('scan_body-help', Horde_Help::link('imp', 'pgp-option-scan-body'));
-    }
-    $t->set('verify_notlocked', !$prefs->isLocked('pgp_verify'));
-    if ($t->get('verify_notlocked')) {
-        $t->set('pgp_verify', $prefs->getValue('pgp_verify'));
-        $t->set('pgp_verify-help', Horde_Help::link('imp', 'pgp-option-verify'));
-    }
-    $t->set('manage_pubkey-help', Horde_Help::link('imp', 'pgp-manage-pubkey'));
-
-    $t->set('empty_pubkey_list', empty($pubkey_list));
-    if (!$t->get('empty_pubkey_list')) {
-        $plist = array();
-        foreach ($pubkey_list as $val) {
-            $linkurl = $selfURL->copy()->add('email', $val['email']);
-            $plist[] = array(
-                'name' => $val['name'],
-                'email' => $val['email'],
-                'view' => Horde::link($linkurl->copy()->add('actionID', 'view_public_key'), sprintf(_("View %s Public Key"), $val['name']), null, 'view_key'),
-                'info' => Horde::link($linkurl->copy()->add('actionID', 'info_public_key'), sprintf(_("Information on %s Public Key"), $val['name']), null, 'info_key'),
-                'delete' => Horde::link($linkurl->copy()->add('actionID', 'delete_public_key'), sprintf(_("Delete %s Public Key"), $val['name']), null, null, "if (confirm('" . addslashes(_("Are you sure you want to delete this public key?")) . "')) { return true; } else { return false; }")
-            );
-        }
-        $t->set('pubkey_list', $plist);
-    }
-
-    $t->set('no_file_upload', !$_SESSION['imp']['file_upload']);
-    if (!$t->get('no_file_upload')) {
-        $t->set('no_source', !$GLOBALS['prefs']->getValue('add_source'));
-        if (!$t->get('no_source')) {
-            $cacheSess = Horde_SessionObjects::singleton();
-            $t->set('public_import_url', Horde::popupJs($selfURL, array('params' => array('actionID' => 'import_public_key', 'reload' => $cacheSess->storeOid($selfURL, false)), 'height' => 275, 'width' => 750, 'urlencode' => true)));
-            $t->set('import_pubkey-help', Horde_Help::link('imp', 'pgp-import-pubkey'));
-        }
-    }
-    $t->set('personalkey-help', Horde_Help::link('imp', 'pgp-overview-personalkey'));
-
-    $t->set('secure_check', !$secure_check);
-    if ($secure_check) {
-        $t->set('has_key', $prefs->getValue('pgp_public_key') && $prefs->getValue('pgp_private_key'));
-        if ($t->get('has_key')) {
-            $t->set('viewpublic', Horde::link($selfURL->copy()->add('actionID', 'view_personal_public_key'), _("View Personal Public Key"), null, 'view_key'));
-            $t->set('infopublic', Horde::link($selfURL->copy()->add('actionID', 'info_personal_public_key'), _("Information on Personal Public Key"), null, 'info_key'));
-            $t->set('sendkey', Horde::link($selfURL->copy()->add('actionID', 'send_public_key'), _("Send Key to Public Keyserver")));
-            $t->set('personalkey-public-help', Horde_Help::link('imp', 'pgp-personalkey-public'));
-
-            $imple = Horde_Ajax_Imple::factory(array('imp', 'PassphraseDialog'), array('type' => 'pgpPersonal'));
-            $imple->attach();
-            $passphrase = $imp_pgp->getPassphrase('personal');
-            $t->set('passphrase', (empty($passphrase)) ? Horde::link('#', _("Enter Passphrase"), null, null, null, null, null, array('id' => $imple->getPassphraseId())) . _("Enter Passphrase") : Horde::link($selfURL->copy()->add('actionID', 'unset_passphrase'), _("Unload Passphrase")) . _("Unload Passphrase"));
-
-            $t->set('viewprivate', Horde::link($selfURL->copy()->add('actionID', 'view_personal_private_key'), _("View Personal Private Key"), null, 'view_key'));
-            $t->set('infoprivate', Horde::link($selfURL->copy()->add('actionID', 'info_personal_private_key'), _("Information on Personal Private Key"), null, 'info_key'));
-            $t->set('personalkey-private-help', Horde_Help::link('imp', 'pgp-personalkey-private'));
-            $t->set('deletekeypair', addslashes(_("Are you sure you want to delete your keypair? (This is NOT recommended!)")));
-            $t->set('personalkey-delete-help', Horde_Help::link('imp', 'pgp-personalkey-delete'));
-        } else {
-            $imp_identity = Horde_Prefs_Identity::singleton(array('imp', 'imp'));
-            $t->set('fullname', $imp_identity->getFullname());
-            $t->set('personalkey-create-name-help', Horde_Help::link('imp', 'pgp-personalkey-create-name'));
-            $t->set('personalkey-create-comment-help', Horde_Help::link('imp', 'pgp-personalkey-create-comment'));
-            $t->set('fromaddr', $imp_identity->getFromAddress());
-            $t->set('personalkey-create-email-help', Horde_Help::link('imp', 'pgp-personalkey-create-email'));
-            $t->set('personalkey-create-keylength-help', Horde_Help::link('imp', 'pgp-personalkey-create-keylength'));
-            $t->set('personalkey-create-passphrase-help', Horde_Help::link('imp', 'pgp-personalkey-create-passphrase'));
-            $t->set('keygen', addslashes(_("Key generation may take a long time to complete.  Continue with key generation?")));
-            $t->set('personal_import_url', Horde::popupJs($selfURL, array('params' => array('actionID' => 'import_personal_public_key'), 'height' => 275, 'width' => 750, 'urlencode' => true)));
-            $t->set('personalkey-create-actions-help', Horde_Help::link('imp', 'pgp-personalkey-create-actions'));
-        }
-    }
-
-} else {
-    $t->set('use_pgp_locked', $prefs->isLocked('use_pgp'));
-    if (!$t->get('use_pgp_locked')) {
-        $t->set('use_pgp_label', Horde::label('use_pgp', _("Enable PGP functionality?")));
-        $t->set('use_pgp_help', Horde_Help::link('imp', 'pgp-overview'));
-    }
-}
-$t->set('prefsurl', Horde::getServiceLink('options', 'imp'));
-
-echo $t->fetch(IMP_TEMPLATES . '/prefs/pgp/pgp.html');
-if (!$chunk) {
-    require $registry->get('templates', 'horde') . '/common-footer.inc';
-}
index 84ec9d5..4be7867 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * S/MIME preferences handling.
+ * S/MIME utilities.
  *
  * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
  *
 require_once dirname(__FILE__) . '/lib/Application.php';
 Horde_Registry::appInit('imp');
 
-$imp_smime = $GLOBALS['injector']->getInstance('IMP_Crypt_Smime');
+$imp_smime = $injector->getInstance('IMP_Crypt_Smime');
+$vars = Horde_Variables::getDefaultVariables();
 
 /* Run through the action handlers */
-$actionID = Horde_Util::getFormData('actionID');
-switch ($actionID) {
-case 'delete_key':
-    $imp_smime->deletePersonalKeys();
-    $notification->push(_("Personal S/MIME keys deleted successfully."), 'horde.success');
-    break;
-
-case 'delete_public_key':
-    try {
-        $imp_smime->deletePublicKey(Horde_Util::getFormData('email'));
-        $notification->push(sprintf(_("S/MIME Public Key for \"%s\" was successfully deleted."), Horde_Util::getFormData('email')), 'horde.success');
-    } catch (Horde_Exception $e) {
-        $notification->push($e);
-    }
-    break;
-
+switch ($vars->actionID) {
 case 'import_public_key':
-    $imp_smime->importKeyDialog('process_import_public_key', Horde_Util::getFormData('reload'));
+    $imp_smime->importKeyDialog('process_import_public_key', $vars->reload);
     exit;
 
 case 'process_import_public_key':
     try {
-        $publicKey = $imp_smime->getImportKey(Horde_Util::getFormData('import_key'));
+        $publicKey = $imp_smime->getImportKey($vars->import_key);
 
         /* Add the public key to the storage system. */
         $imp_smime->addPublicKey($publicKey);
         $notification->push(_("S/MIME Public Key successfully added."), 'horde.success');
-        $imp_smime->reloadWindow(Horde_Util::getFormData('reload'));
+        $imp_smime->reloadWindow($vars->reload);
     } catch (Horde_Browser_Exception $e) {
         $notification->push(_("No S/MIME public key imported."), 'horde.error');
         throw new Horde_Exception_Prior($e);
     } catch (Horde_Exception $e) {
         $notification->push($e);
-        $actionID = 'import_public_key';
-        $imp_smime->importKeyDialog('process_import_public_key', Horde_Util::getFormData('reload'));
+        $vars->actionID = 'import_public_key';
+        $imp_smime->importKeyDialog('process_import_public_key', $vars->reload);
     }
     exit;
 
 case 'view_public_key':
 case 'info_public_key':
     try {
-        $key = $imp_smime->getPublicKey(Horde_Util::getFormData('email'));
+        $key = $imp_smime->getPublicKey($vars->email);
     } catch (Horde_Exception $e) {
         $key = $e->getMessage();
     }
-    if ($actionID == 'view_public_key') {
+    if ($vars->actionID == 'view_public_key') {
         $imp_smime->textWindowOutput('S/MIME Public Key', $key);
     } else {
         $imp_smime->printCertInfo($key);
@@ -83,28 +69,28 @@ case 'view_personal_private_key':
     exit;
 
 case 'import_personal_certs':
-    $imp_smime->importKeyDialog('process_import_personal_certs', Horde_Util::getFormData('reload'));
+    $imp_smime->importKeyDialog('process_import_personal_certs', $vars->reload);
     exit;
 
 case 'process_import_personal_certs':
     try {
-        $pkcs12 = $imp_smime->getImportKey(Horde_Util::getFormData('import_key'));
-        $imp_smime->addFromPKCS12($pkcs12, Horde_Util::getFormData('upload_key_pass'), Horde_Util::getFormData('upload_key_pk_pass'));
+        $pkcs12 = $imp_smime->getImportKey($vars->import_key);
+        $imp_smime->addFromPKCS12($pkcs12, $vars->upload_key_pass, $vars->upload_key_pk_pass);
         $notification->push(_("S/MIME Public/Private Keypair successfully added."), 'horde.success');
-        $imp_smime->reloadWindow(Horde_Util::getFormData('reload'));
+        $imp_smime->reloadWindow($vars->reload);
     } catch (Horde_Browser_Exception $e) {
         throw new Horde_Exception_Prior($e);
     } catch (Horde_Exception $e) {
         $notification->push(_("Personal S/MIME certificates NOT imported: ") . $e->getMessage(), 'horde.error');
-        $actionID = 'import_personal_certs';
-        $imp_smime->importKeyDialog('process_import_personal_certs', Horde_Util::getFormData('reload'));
+        $vars->actionID = 'import_personal_certs';
+        $imp_smime->importKeyDialog('process_import_personal_certs', $vars->reload);
     }
     exit;
 
 case 'save_attachment_public_key':
     /* Retrieve the key from the message. */
-    $contents = IMP_Contents::singleton(Horde_Util::getFormData('uid') . IMP::IDX_SEP . Horde_Util::getFormData('mailbox'));
-    $mime_part = $contents->getMIMEPart(Horde_Util::getFormData('mime_id'));
+    $contents = IMP_Contents::singleton($vars->uid . IMP::IDX_SEP . $vars->mailbox);
+    $mime_part = $contents->getMIMEPart($vars->mime_id);
     if (empty($mime_part)) {
         throw new IMP_Exception('Cannot retrieve public key from message.');
     }
@@ -117,113 +103,4 @@ case 'save_attachment_public_key':
         $notification->push(_("No Certificate found"), 'horde.error');
     }
     exit;
-
-case 'unset_passphrase':
-    if ($imp_smime->getPassphrase() !== false) {
-        $imp_smime->unsetPassphrase();
-        $notification->push(_("Passphrase successfully unloaded."), 'horde.success');
-    }
-    break;
-
-case 'save_options':
-    $prefs->setValue('use_smime', Horde_Util::getFormData('use_smime') ? 1 : 0);
-    $prefs->setValue('smime_verify', Horde_Util::getFormData('smime_verify') ? 1 : 0);
-    $notification->push(_("Preferences successfully updated."), 'horde.success');
-    break;
-}
-
-/* Get list of Public Keys. */
-try {
-    $pubkey_list = $imp_smime->listPublicKeys();
-} catch (Horde_Exception $e) {
-    $pubkey_list = array();
-    $notification->push($e);
-}
-
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_Ui::generateHeader('imp', null, 'smime', $chunk);
-
-$selfURL = Horde::applicationUrl('smime.php');
-
-/* If S/MIME preference not active, or openssl PHP extension not available, do
- * NOT show S/MIME Admin screen. */
-try {
-    $imp_smime->checkForOpenSSL();
-    $openssl_check = true;
-} catch (Horde_Exception $e) {
-    $openssl_check = false;
-}
-
-/* If S/MIME preference not active, do NOT show S/MIME Admin screen. */
-$t = $injector->createInstance('Horde_Template');
-$t->setOption('gettext', true);
-$t->set('use_smime_help', Horde_Help::link('imp', 'smime-overview'));
-if ($openssl_check && $prefs->getValue('use_smime')) {
-    Horde::addScriptFile('imp.js', 'imp');
-    $t->set('smimeactive', true);
-    $t->set('manage_pubkey-help', Horde_Help::link('imp', 'smime-manage-pubkey'));
-
-    $t->set('verify_notlocked', !$prefs->isLocked('smime_verify'));
-    if ($t->get('verify_notlocked')) {
-        $t->set('smime_verify', $prefs->getValue('smime_verify'));
-        $t->set('smime_verify-help', Horde_Help::link('imp', 'smime-option-verify'));
-    }
-
-    $t->set('empty_pubkey_list', empty($pubkey_list));
-    if (!$t->get('empty_pubkey_list')) {
-        $plist = array();
-        foreach ($pubkey_list as $val) {
-            $linkurl = $selfURL->copy()->add('email', $val['email']);
-            $plist[] = array(
-                'name' => $val['name'],
-                'email' => $val['email'],
-                'view' => Horde::link($linkurl->copy()->add('actionID', 'view_public_key'), sprintf(_("View %s Public Key"), $val['name']), null, 'view_key'),
-                'info' => Horde::link($linkurl->copy()->add('actionID', 'info_public_key'), sprintf(_("Information on %s Public Key"), $val['name']), null, 'info_key'),
-                'delete' => Horde::link($linkurl->copy()->add('actionID', 'delete_public_key'), sprintf(_("Delete %s Public Key"), $val['name']), null, null, "if (confirm('" . addslashes(_("Are you sure you want to delete this public key?")) . "')) { return true; } else { return false; }")
-            );
-        }
-        $t->set('pubkey_list', $plist);
-    }
-
-    $t->set('no_file_upload', !$_SESSION['imp']['file_upload']);
-    if (!$t->get('no_file_upload')) {
-        $t->set('no_source', !$GLOBALS['prefs']->getValue('add_source'));
-        if (!$t->get('no_source')) {
-            $cacheSess = Horde_SessionObjects::singleton();
-            $t->set('public_import_url', Horde::popupJs($selfURL, array('params' => array('actionID' => 'import_public_key', 'reload' => $cacheSess->storeOid($selfURL, false)), 'height' => 275, 'width' => 750, 'urlencode' => true)));
-            $t->set('import_pubkey-help', Horde_Help::link('imp', 'smime-import-pubkey'));
-        }
-    }
-    $t->set('personalkey-help', Horde_Help::link('imp', 'smime-overview-personalkey'));
-
-    $t->set('secure_check', Horde::isConnectionSecure());
-    if ($t->get('secure_check')) {
-        $t->set('has_key', $prefs->getValue('smime_public_key') && $prefs->getValue('smime_private_key'));
-        if ($t->get('has_key')) {
-            $t->set('viewpublic', Horde::link($selfURL->copy()->add('actionID', 'view_personal_public_key'), _("View Personal Public Key"), null, 'view_key'));
-            $t->set('infopublic', Horde::link($selfURL->copy()->add('actionID', 'info_personal_public_key'), _("Information on Personal Public Key"), null, 'info_key'));
-            $imple = Horde_Ajax_Imple::factory(array('imp', 'PassphraseDialog'), array('type' => 'smimePersonal'));
-            $imple->attach();
-            $passphrase = $imp_smime->getPassphrase();
-            $t->set('passphrase', (empty($passphrase)) ? Horde::link('#', _("Enter Passphrase"), null, null, null, null, null, array('id' => $imple->getPassphraseId())) . _("Enter Passphrase") : Horde::link($selfURL->copy()->add('actionID', 'unset_passphrase'), _("Unload Passphrase")) . _("Unload Passphrase"));
-
-            $t->set('viewprivate', Horde::link($selfURL->copy()->add('actionID', 'view_personal_private_key'), _("View Personal Private Key"), null, 'view_key'));
-            $t->set('deletekeypair', addslashes(_("Are you sure you want to delete your keypair? (This is NOT recommended!)")));
-            $t->set('personalkey-delete-help', Horde_Help::link('imp', 'smime-delete-personal-certs'));
-        } else {
-            $t->set('personal_import_url', Horde::popupJs($selfURL, array('params' => array('actionID' => 'import_personal_certs'), 'height' => 275, 'width' => 750, 'urlencode' => true)));
-            $t->set('import-cert-help', Horde_Help::link('imp', 'smime-import-personal-certs'));
-        }
-    }
-} else {
-    $t->set('use_smime_locked', $prefs->isLocked('use_smime'));
-    if (!$t->get('use_smime_locked')) {
-        $t->set('use_smime_label', Horde::label('use_smime', _("Enable S/MIME functionality?")));
-    }
-}
-$t->set('prefsurl', Horde::getServiceLink('options', 'imp'));
-
-echo $t->fetch(IMP_TEMPLATES . '/prefs/smime/smime.html');
-if (!$chunk) {
-    require $registry->get('templates', 'horde') . '/common-footer.inc';
 }
diff --git a/imp/stationery.php b/imp/stationery.php
deleted file mode 100644 (file)
index 27bf694..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-<?php
-/**
- * Copyright 2005-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author  Jan Schneider <jan@horde.org>
- * @package IMP
- */
-
-require_once dirname(__FILE__) . '/lib/Application.php';
-Horde_Registry::appInit('imp', array('authentication' => 'horde'));
-
-$compose_url = Horde::getServiceLink('options', 'imp');
-
-/* Is the preference locked? */
-if ($prefs->isLocked('stationery')) {
-    header('Location: ' . $compose_url);
-    exit;
-}
-
-/* Retrieve stationery. */
-$stationery_list = @unserialize($prefs->getValue('stationery', false));
-$stationery_list = is_array($stationery_list)
-    ? Horde_String::convertCharset($stationery_list, $prefs->getCharset())
-    : array();
-
-/* Get form data. */
-$selected = Horde_Util::getFormData('stationery');
-if (strlen($selected)) {
-    $selected = (int)$selected;
-}
-
-/* Always check for stationery type switches. */
-$content = Horde_Util::getFormData('content', '');
-$last_type = Horde_Util::getFormData('last_type');
-$name = Horde_Util::getFormData('name', '');
-$type = Horde_Util::getFormData('type', 'plain');
-if (!empty($last_type) && $last_type != $type) {
-    $content = ($type == 'plain')
-        ? Horde_Text_Filter::filter($content, 'Html2text', array('charset' => Horde_Nls::getCharset()))
-        : nl2br(htmlspecialchars(htmlspecialchars($content)));
-}
-$stationery = array('n' => $name, 't' => $type, 'c' => $content);
-
-/* Run through the action handlers. */
-$actionID = Horde_Util::getFormData('actionID');
-$updated = false;
-switch ($actionID) {
-case 'update':
-    if (Horde_Util::getFormData('edit')) {
-        /* Stationery has been switched. */
-        if (strlen($selected)) {
-            /* Edit existing. */
-            $stationery = array(
-                'n' => $stationery_list[$selected]['n'],
-                't' => $stationery_list[$selected]['t'],
-                'c' => $stationery_list[$selected]['c']
-            );
-        } else {
-            $stationery = array(
-                'n' => '',
-                't' => 'plain',
-                'c' => ''
-            );
-        }
-    } elseif (Horde_Util::getFormData('delete')) {
-        /* Delete stationery. */
-        if (isset($stationery_list[$selected])) {
-            $updated = sprintf(_("The stationery \"%s\" has been deleted."), $stationery_list[$selected]['n']);
-            unset($stationery_list[$selected]);
-            $selected = null;
-        }
-        $stationery = array(
-            'n' => '',
-            't' => 'plain',
-            'c' => ''
-        );
-    } elseif (Horde_Util::getFormData('save')) {
-        /* Saving stationery. */
-        if (!strlen($selected)) {
-            $selected = count($stationery_list);
-            $stationery_list[] = $stationery;
-            $updated = sprintf(_("The stationery \"%s\" has been added."), $stationery['n']);
-        } else {
-            $stationery_list[$selected] = $stationery;
-            $updated = sprintf(_("The stationery \"%s\" has been updated."), $stationery['n']);
-        }
-    }
-    break;
-}
-
-if ($updated) {
-    $prefs->setValue('stationery', serialize(Horde_String::convertCharset($stationery_list, Horde_Nls::getCharset(), $prefs->getCharset())), false);
-    $notification->push($updated, 'horde.success');
-}
-
-if ($stationery['t'] == 'html') {
-    $injector->getInstance('Horde_Editor')->getEditor('Ckeditor', array('id' => 'content'));
-}
-
-/* Show the header. */
-$chunk = Horde_Util::nonInputVar('chunk');
-Horde_Prefs_Ui::generateHeader('imp', null, null, $chunk);
-
-$t = $injector->createInstance('Horde_Template');
-$t->setOption('gettext', true);
-$t->set('action', Horde::selfUrl());
-$t->set('forminput', Horde_Util::formInput());
-$t->set('navcell', Horde_Util::bufferOutput(array('Horde_Prefs_Ui', 'generateNavigationCell'), 'imp', 'compose'));
-
-$slist = array();
-foreach ($stationery_list as $key => $choice) {
-    $slist[] = array(
-        'val' => $key,
-        'selected' => ($selected === $key),
-        'text' => $choice['n'] . ' ' . ($choice['t'] == 'html' ? _("(HTML)") : _("(Plain Text)"))
-    );
-}
-$t->set('slist', $slist);
-$t->set('selected', strlen($selected));
-$t->set('last_type', $stationery['t']);
-$t->set('name_label', Horde::label('name', _("Stationery name:")));
-$t->set('name', $stationery['n']);
-$t->set('type_label', Horde::label('name', _("Stationery type:")));
-$t->set('plain', $stationery['t'] == 'plain');
-$t->set('html', $stationery['t'] == 'html');
-$t->set('content_label', Horde::label('content', _("Stationery:")));
-$t->set('content', $stationery['c']);
-$t->set('button_href', $compose_url->copy()->add('group', 'compose'));
-$t->set('button_val', htmlspecialchars(_("Return to Message Composition"), ENT_COMPAT, Horde_Nls::getCharset()));
-
-echo $t->fetch(IMP_TEMPLATES . '/prefs/stationery/stationery.html');
-if (!$chunk) {
-    require $registry->get('templates', 'horde') . '/common-footer.inc';
-}
diff --git a/imp/templates/imp/acl/acl.html b/imp/templates/imp/acl/acl.html
deleted file mode 100644 (file)
index 9fd0a26..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-<form method="post" name="folders" id="folders" action="<tag:aclurl />">
-<input type="hidden" name="actionID" value="" />
-<tag:forminput />
-
-<div class="header">
- <tag:aclnavcell />
- <gettext>Share mail folders</gettext>
-</div>
-
-<div class="header">
- <ul>
-  <li>
-   <label for="aclfolder" class="hidden"><gettext>Change Folder</gettext></label>
-   <tag:changefolder /><span class="folderImg"></span></a> <select id="aclfolder" name="folder"><tag:options /></select>
-  </li>
- </ul>
- <span class="smallheader"><tag:current /></span>
-</div>
-</form>
-
-<form method="post" name="acl" id="acl" action="<tag:aclurl />">
-<input type="hidden" name="actionID" value="imp_acl_set" />
-<input type="hidden" name="folder" value="<tag:folder />" />
-<tag:forminput />
-<table cellspacing="0" width="100%">
-<if:noacl>
- <tr>
-  <td colspan="<tag:maxrule />" class="item leftAlign">
-   <em><strong> <gettext>The current list of users with access to this folder could not be retrieved.</gettext></strong></em>
-  </td>
-  <td class="item leftAlign">&nbsp;</td>
- </tr>
- <tr>
-  <td colspan="<tag:maxrule />" class="header">
-   <input type="button" class="button" name="back" onclick="$('acl').disable(); document.location.href='<tag:prefsurl />'" value="<gettext>Return to Options</gettext>" />
-  </td>
-  <td class="header">&nbsp;</td>
- </tr>
-<else:noacl>
-<tr>
- <th class="item" width="<tag:width />">
-  <h3><strong><gettext>User</gettext></strong></h3>
- </th>
-<loop:rights>
- <th class="item" width="<tag:width />">
-  <h4><strong><span title="<tag:rights.desc />"><tag:rights.title /></span></strong></h4>
- </th>
-</loop:rights>
-</tr>
-<loop:curr_acl>
-<tr>
- <td class="item"><tag:curr_acl.index /><input id="<tag:curr_acl.index />" type="hidden" name="acl[<tag:curr_acl.index />][]" value="" /></td>
-<loop:curr_acl.rule>
- <td class="item" align="center">
-  <label class="hidden" for="<tag:curr_acl.index />:<tag:curr_acl.rule.val />">Rule <tag:curr_acl.rule.val /> for user <tag:curr_acl.index /></label>
-  <input type="checkbox" class="checkbox" id="<tag:curr_acl.index />:<tag:curr_acl.rule.val />"
-  <if:curr_acl.disabled> disabled="disabled"<else:curr_acl.disabled><if:canedit> name="acl[<tag:curr_acl.index />][]" value="<tag:curr_acl.rule.val />"<else:canedit> disabled="disabled"</else:canedit></if:canedit></else:curr_acl.disabled></if:curr_acl.disabled><if:curr_acl.rule.enabled> checked="checked"</if:curr_acl.rule.enabled> />
- </td>
-</loop:curr_acl.rule>
-</tr>
-</loop:curr_acl>
-
-<if:canedit>
-<tr>
- <td class="item">
-  <label for="new_user" class="hidden">New User</label><tag:new_user />
- </td>
-<loop:rights>
- <td class="item" align="center">
-  <label class="hidden" for="new_user:<tag:rights.right />">Rule <tag:rights.right /> for the new user</label><input id="new_user:<tag:rights.right />" type="checkbox" name="new_acl[]" value="<tag:rights.right />" class="checkbox" />
- </td>
-</loop:rights>
-</tr>
-<tr>
- <td>&nbsp;</td>
-</tr>
-<tr>
- <td colspan="<tag:maxrule />" class="header">
-  <input type="button" class="button" id="fbutton" name="fbutton" onclick="$('acl').submit(); $('acl').disable();" value="<gettext>Save</gettext>" />
-  <input type="button" class="button" id="resetbut" name="resetbut" value="<gettext>Reset</gettext>" />
-  <input type="button" class="button" id="back" name="back" onclick="$('acl').disable(); document.location.href='<tag:prefsurl />'" value="<gettext>Return to Options</gettext>" />
- </td>
- <td class="header">&nbsp;</td>
-</tr>
-<else:canedit>
-<tr>
- <td colspan="<tag:maxrule />" class="item leftAlign">
-  <em><strong><gettext>You do not have permission to change access to this folder.</gettext></strong></em>
- </td>
- <td class="item leftAlign">&nbsp;</td>
-</tr>
-
-<tr>
- <td colspan="<tag:maxrule />" class="header">
-  <input type="button" class="button" name="back" onclick="$('acl').disable(); document.location.href='<tag:prefsurl />'" value="<gettext>Return to Options</gettext>" />
- </td>
- <td class="header">&nbsp;</td>
-</tr>
-</else:canedit></if:canedit>
-</else:noacl></if:noacl>
-</table>
-</form>
diff --git a/imp/templates/pgp/import_key.html b/imp/templates/pgp/import_key.html
new file mode 100644 (file)
index 0000000..8233115
--- /dev/null
@@ -0,0 +1,56 @@
+<form enctype="multipart/form-data" method="post" name="import_pgp_key" action="<tag:selfurl />">
+<if:broken_mp_form>
+<input type="hidden" name="msie_formdata_is_broken" value="" />
+</if:broken_mp_form>
+<input type="hidden" name="reload" value="<tag:reload />" />
+<input type="hidden" name="actionID" value="<tag:target />" />
+<tag:forminput />
+
+<table border="0" cellspacing="0" cellpadding="2" width="100%">
+ <tr>
+  <td class="header leftAlign nowrap"><if:import_public_key><gettext>Import Public PGP Key</gettext></if:import_public_key><if:import_personal_public_key><gettext>Import Personal Public PGP Key</gettext></if:import_personal_public_key><if:import_personal_private_key><gettext>Import Personal Private PGP Key</gettext></if:import_personal_private_key></td>
+ </tr>
+
+ <tr>
+  <td class="item leftAlign">
+   <table border="0" cellpadding="0" width="100%">
+    <tr>
+     <td class="item leftAlign"><label for="import_key"><strong><if:import_public_key><gettext>Import Public PGP Key Here:</gettext></if:import_public_key><if:import_personal_public_key><gettext>Import Personal Public PGP Key Here:</gettext></if:import_personal_public_key><if:import_personal_private_key><gettext>Import Personal Private PGP Key Here:</gettext></if:import_personal_private_key></strong></label></td>
+    </tr>
+    <tr>
+     <td class="item leftAlign">
+      <textarea id="import_key" name="import_key" rows="6" cols="80" class="fixed"></textarea>
+     </td>
+    </tr>
+   </table>
+  </td>
+ </tr>
+
+ <tr>
+  <td class="item leftAlign"><font color="red"><strong>--<gettext>OR</gettext>--</strong></font></td>
+ </tr>
+
+ <tr>
+  <td class="item leftAlign">
+   <table border="0" cellpadding="0" width="100%">
+    <tr>
+     <td class="item leftAlign">
+      <label for="upload_key"><strong><gettext>Upload:</gettext></strong></label>&nbsp;
+      <input id="upload_key" name="upload_key" type="file" size="40" />
+     </td>
+    </tr>
+   </table>
+  </td>
+ </tr>
+
+ <tr>
+  <td align="center" class="header nowrap">
+   <input type="submit" name="import" class="button" value="<gettext>Import Key</gettext>" />
+   <input type="submit" name="import" class="button" onclick="window.close();" value="<gettext>Cancel</gettext>" />
+  </td>
+ </tr>
+</table>
+
+</form>
+</body>
+</html>
diff --git a/imp/templates/prefs/accounts.html b/imp/templates/prefs/accounts.html
new file mode 100644 (file)
index 0000000..f7135e5
--- /dev/null
@@ -0,0 +1,91 @@
+<input type="hidden" name="accounts_action" id="accounts_action" />
+<input type="hidden" name="accounts_data" id="accounts_data" />
+
+<if:new>
+<table class="accountsmanagement">
+ <tr>
+  <td class="item"><gettext>Label</gettext>:</td>
+  <td class="item"><input name="accounts_label" size="30"/></td>
+  <td></td>
+ </tr>
+ <tr>
+  <td class="item"><gettext>Type</gettext>:</td>
+  <td class="item">
+   <select name="accounts_type">
+    <option value="imap" selected="selected"><gettext>IMAP</gettext></option>
+    <option value="pop3"><gettext>POP3</gettext></option>
+   </select>
+  </td>
+  <td class="required">*</td>
+ </tr>
+ <tr>
+  <td class="item"><gettext>Server</gettext>:</td>
+  <td class="item"><input name="accounts_server" size="30"/></td>
+  <td class="required">*</td>
+ </tr>
+ <tr>
+  <td class="item"><gettext>Username</gettext>:</td>
+  <td class="item"><input name="accounts_username" size="30"/></td>
+  <td class="required">*</td>
+ </tr>
+ <tr>
+  <td class="item"><gettext>Port</gettext>:</td>
+  <td class="item"><input name="accounts_port" size="10"/></td>
+  <td></td>
+ </tr>
+ <tr>
+  <td class="item"><gettext>Use secure connection?</gettext></td>
+  <td class="item">
+   <select name="accounts_secure">
+    <option value="yes" selected="selected"><gettext>Required</gettext></option>
+    <option value="auto" selected="selected"><gettext>Use if available</gettext></option>
+    <option value="no" selected="selected"><gettext>Never</gettext></option>
+   </select>
+  </td>
+  <td></td>
+ </tr>
+</table>
+
+<input id="add_button" type="button" class="button" value="<gettext>Save</gettext>" />
+<input id="cancel_button" type="button" class="button" value="<gettext>Cancel</gettext>" />
+<else:new>
+<table class="accountsmanagement">
+ <thead>
+  <tr>
+   <td><gettext>Label</gettext></td>
+   <td><gettext>Server</gettext></td>
+   <td><gettext>Type</gettext></td>
+   <td><gettext>Port</gettext></td>
+   <td><gettext>Secure</gettext>?</td>
+   <td></td>
+  </tr>
+ </thead>
+ <tbody>
+<if:accounts>
+<loop:accounts>
+  <tr id="accountsid_<tag:accounts.id />">
+   <td><tag:accounts.label /></td>
+   <td><tag:accounts.server /></td>
+   <td><tag:accounts.type /></td>
+   <td><tag:accounts.port /></td>
+<if:accounts.secure_auto>
+   <td><gettext>Auto</gettext></td>
+<else:accounts.secure_auto>
+<if:accounts.secure>
+   <td class="accountsSecure"><gettext>Yes</gettext></td>
+<else:accounts.secure>
+   <td class="accountsNotSecure"><gettext>No</gettext></td>
+</else:accounts.secure></if:accounts.secure></else:accounts,secure_auto></if:accounts.secure_auto>
+   <td><a class="accountsdelete" href="#"><tag:delete_img /></a></td>
+  </tr>
+</loop:accounts>
+<else:accounts>
+  <tr>
+   <td class="noneconfigured" colspan="3"><gettext>No accounts configured</gettext></td>
+  </tr>
+</else:accounts></if:accounts>
+ </tbody>
+</table>
+
+<input id="new_button" type="submit" class="button" value="<gettext>Add Account</gettext>" />
+</else:new></if:new>
diff --git a/imp/templates/prefs/accountsmanagement.inc b/imp/templates/prefs/accountsmanagement.inc
deleted file mode 100644 (file)
index 05eb85c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<input type="hidden" name="accounts_action" id="accounts_action" />
-<input type="hidden" name="accounts_data" id="accounts_data" />
-
-<?php if (Horde_Util::getFormData('accounts_action') == 'new'): ?>
-<table class="accountsmanagement">
- <tr>
-  <td class="item"><?php echo _("Label") ?>:</td>
-  <td class="item"><input name="accounts_label" size="30"/></td>
-  <td></td>
- </tr>
- <tr>
-  <td class="item"><?php echo _("Type") ?>:</td>
-  <td class="item">
-   <select name="accounts_type">
-    <option value="imap" selected="selected"><?php echo _("IMAP") ?></option>
-    <option value="pop3"><?php echo _("POP3") ?></option>
-   </select>
-  </td>
-  <td class="required">*</td>
- </tr>
- <tr>
-  <td class="item"><?php echo _("Server") ?>:</td>
-  <td class="item"><input name="accounts_server" size="30"/></td>
-  <td class="required">*</td>
- </tr>
- <tr>
-  <td class="item"><?php echo _("Username") ?>:</td>
-  <td class="item"><input name="accounts_username" size="30"/></td>
-  <td class="required">*</td>
- </tr>
- <tr>
-  <td class="item"><?php echo _("Port") ?>:</td>
-  <td class="item"><input name="accounts_port" size="10"/></td>
-  <td></td>
- </tr>
- <tr>
-  <td class="item"><?php echo _("Use secure connection?") ?></td>
-  <td class="item">
-   <select name="accounts_secure">
-    <option value="yes" selected="selected"><?php echo _("Required") ?></option>
-    <option value="auto" selected="selected"><?php echo _("Use if available") ?></option>
-    <option value="no" selected="selected"><?php echo _("Never") ?></option>
-   </select>
-  </td>
-  <td></td>
- </tr>
-</table>
-
-<input id="add_button" type="button" class="button" value="<?php echo _("Save") ?>" />
-<input id="cancel_button" type="button" class="button" value="<?php echo _("Cancel") ?>" />
-<?php else: ?>
-<?php
-$accounts_list = $GLOBALS['injector']->getInstance('IMP_Accounts')->getList();
-$delete_img = Horde::img('delete.png');
-?>
-
-<table class="accountsmanagement">
- <thead>
-  <tr>
-   <td><?php echo _("Label") ?></td>
-   <td><?php echo _("Server") ?></td>
-   <td><?php echo _("Type") ?></td>
-   <td><?php echo _("Port") ?></td>
-   <td><?php echo _("Secure") ?>?</td>
-   <td></td>
-  </tr>
- </thead>
- <tbody>
-<?php if (empty($accounts_list)): ?>
-  <tr>
-   <td class="noneconfigured" colspan="3"><?php echo _("No accounts configured") ?></td>
-  </tr>
-<?php else: ?>
-<?php foreach ($accounts_list as $key => $val): ?>
-  <tr id="accountsid_<?php echo $key ?>">
-   <td><?php echo htmlspecialchars($val['label']) ?></td>
-   <td><?php echo htmlspecialchars($val['server']) ?></td>
-   <td><?php echo htmlspecialchars($val['type']) ?></td>
-   <td><?php echo htmlspecialchars($val['port']) ?></td>
-<?php if ($val['secure'] == 'auto'): ?>
-   <td><?php echo _("Auto") ?></td>
-<?php elseif ($val['secure'] == 'yes'): ?>
-   <td class="accountsSecure"><?php echo _("Yes") ?></td>
-<?php else: ?>
-   <td class="accountsNotSecure"><?php echo _("No") ?></td>
-<?php endif; ?>
-   <td><a class="accountsdelete" href="#"><?php echo $delete_img ?></a></td>
-  </tr>
-<?php endforeach; ?>
-<?php endif; ?>
- </tbody>
-</table>
-
-<input id="new_button" type="submit" class="button" value="<?php echo _("Add Account") ?>" />
-<?php endif; ?>
diff --git a/imp/templates/prefs/acl.html b/imp/templates/prefs/acl.html
new file mode 100644 (file)
index 0000000..b7d4786
--- /dev/null
@@ -0,0 +1,79 @@
+<input type="hidden" name="acl_folder" value="<tag:folder />" />
+
+<div>
+ <h3><tag:current /></h3>
+</div>
+
+<table cellspacing="0" width="100%">
+<if:noacl>
+ <tr>
+  <td colspan="<tag:maxrule />" class="item leftAlign">
+   <em><strong> <gettext>The current list of users with access to this folder could not be retrieved.</gettext></strong></em>
+  </td>
+  <td></td>
+ </tr>
+<else:noacl>
+<tr>
+ <th class="item" width="<tag:width />">
+  <h4><strong><gettext>User</gettext></strong></h4>
+ </th>
+<loop:rights>
+ <th class="item" width="<tag:width />">
+  <h4><strong><span title="<tag:rights.desc />"><tag:rights.title /></span></strong></h4>
+ </th>
+</loop:rights>
+</tr>
+<loop:curr_acl>
+<tr>
+ <td class="item"><tag:curr_acl.index /><input id="<tag:curr_acl.index />" type="hidden" name="acl[<tag:curr_acl.index />][]" value="" /></td>
+<loop:curr_acl.rule>
+ <td class="item" align="center">
+  <label class="hidden" for="<tag:curr_acl.index />:<tag:curr_acl.rule.val />">Rule <tag:curr_acl.rule.val /> for user <tag:curr_acl.index /></label>
+  <input type="checkbox" class="checkbox" id="<tag:curr_acl.index />:<tag:curr_acl.rule.val />"
+  <if:curr_acl.disabled> disabled="disabled"<else:curr_acl.disabled><if:canedit> name="acl[<tag:curr_acl.index />][]" value="<tag:curr_acl.rule.val />"<else:canedit> disabled="disabled"</else:canedit></if:canedit></else:curr_acl.disabled></if:curr_acl.disabled><if:curr_acl.rule.enabled> checked="checked"</if:curr_acl.rule.enabled> />
+ </td>
+</loop:curr_acl.rule>
+</tr>
+</loop:curr_acl>
+
+<if:canedit>
+<tr>
+ <td class="item">
+   <label for="new_user" class="hidden">New User</label>
+<if:noadmin>
+   <input id="new_user" type="text" name="new_user" />
+<else:noadmin>
+   <select id="new_user" name="new_user">
+<loop:new_user>
+    <option><tag:new_user /></option>
+</loop:new_user>
+   </select>
+</else:noadmin></if:noadmin>
+ </td>
+<loop:rights>
+ <td class="item" align="center">
+  <label class="hidden" for="new_user:<tag:rights.right />">Rule <tag:rights.right /> for the new user</label><input id="new_user:<tag:rights.right />" type="checkbox" name="new_acl[]" value="<tag:rights.right />" class="checkbox" />
+ </td>
+</loop:rights>
+</tr>
+<tr>
+ <td></td>
+</tr>
+<else:canedit>
+<tr>
+ <td colspan="<tag:maxrule />" class="item leftAlign">
+  <em><strong><gettext>You do not have permission to change access to this folder.</gettext></strong></em>
+ </td>
+ <td></td>
+</tr>
+</else:canedit></if:canedit>
+</else:noacl></if:noacl>
+</table>
+
+<div>
+ <span class="folderImg"></span>
+ <select id="aclfolder" name="folder">
+  <tag:options />
+ </select>
+ <input type="submit" name="change_acl_folder" class="button" value="<gettext>Change Folder</gettext>" />
+</div>
diff --git a/imp/templates/prefs/drafts.html b/imp/templates/prefs/drafts.html
new file mode 100644 (file)
index 0000000..dc253dc
--- /dev/null
@@ -0,0 +1,12 @@
+<div>
+ <div>
+  <tag:label />
+ </div>
+ <div>
+  <input type="hidden" name="drafts_new" id="drafts_new" value="" />
+  <select id="drafts" name="drafts">
+   <option value="<tag:nofolder />"><gettext>None</gettext></option>
+   <tag:flist />
+  </select>
+ </div>
+</div>
diff --git a/imp/templates/prefs/draftsselect.inc b/imp/templates/prefs/draftsselect.inc
deleted file mode 100644 (file)
index 499ccd4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<div>
- <div>
-  <?php echo Horde::label('drafts', _("Drafts folder:")) ?>
- </div>
- <div>
-  <input type="hidden" name="drafts_new" id="drafts_new" value="" />
-  <select id="drafts" name="drafts">
-   <option value="<?php echo IMP::PREF_NO_FOLDER ?>"><?php echo _("None") ?></option>
-   <?php echo IMP::flistSelect(array('heading' => _("Create a new drafts folder"), 'filter' => array('INBOX'), 'selected' => IMP::folderPref($prefs->getValue('drafts_folder'), true), 'new_folder' => true)) ?>
-  </select>
- </div>
-</div>
diff --git a/imp/templates/prefs/encrypt.html b/imp/templates/prefs/encrypt.html
new file mode 100644 (file)
index 0000000..ae2f85b
--- /dev/null
@@ -0,0 +1,10 @@
+<div>
+ <div>
+  <tag:label />
+ </div>
+ <div>
+  <select id="default_encrypt" name="default_encrypt">
+   <tag:elist />
+  </select>
+ </div>
+</div>
diff --git a/imp/templates/prefs/encryptselect.inc b/imp/templates/prefs/encryptselect.inc
deleted file mode 100644 (file)
index 8bfc7d0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<div>
- <div><?php echo Horde::label('default_encrypt', _("Your default encryption method for sending messages:")) ?></div>
- <div>
-  <select id="default_encrypt" name="default_encrypt">
-   <?php echo IMP::encryptList() ?>
-  </select>
- </div>
-</div>
diff --git a/imp/templates/prefs/filters/filters.html b/imp/templates/prefs/filters/filters.html
deleted file mode 100644 (file)
index 5864cc1..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<div class="header">
- <tag:navcell /> <gettext>Filter Settings</gettext>
-</div>
-
-<if:notactive>
-<div class="prefsContainer item">
- <em><gettext>Filter support is disabled on this system.</gettext></em>
-
- <p><input type="button" name="back" class="button" onclick="document.location.href='<tag:prefsurl />'" value="<tag:return_text />" /></p>
-</div>
-<else:notactive>
-<div class="prefsContainer item">
-<form method="post" name="prefs" action="<tag:selfurl />">
-<tag:forminput />
-<input type="hidden" name="actionID" value="update_prefs" />
-<input type="hidden" name="group" value="<tag:group />" />
-<input type="hidden" name="app" value="<tag:app />" />
-
-<loop:links>
-<tag:links.img /> &nbsp;<tag:links.link /><tag:links.text /></a> &nbsp;<tag:links.help /><br />
-</loop:links>
-
-<if:opts>
-<br />
-<loop:opts>
-<input type="checkbox" id="filter_<tag:opts.key />" name="filter_<tag:opts.key />" <if:opts.checked>checked="checked" </if:opts.checked>/> &nbsp;<tag:opts.label /> &nbsp;<tag:opts.help /><br />
-</loop:opts>
-
-<p>
- <input type="submit" name="save" class="button" onclick="document.prefs.actionID.value='update_prefs';return true;" value="<tag:save_opts />" />&nbsp;&nbsp;
- <input id="prefs_return" type="button" name="back" class="button" onclick="document.location.href='<tag:prefsurl />'" value="<tag:return_text />" />
-</p>
-</if:opts>
-
-</form>
-</div>
-</else:notactive></if:notactive>
diff --git a/imp/templates/prefs/flagmanagement.inc b/imp/templates/prefs/flagmanagement.inc
deleted file mode 100644 (file)
index b3a11ca..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/* Get the list of flags. */
-$flaglist = $GLOBALS['injector']->getInstance('IMP_Imap_Flags')->getList(array('div' => true, 'fgcolor' => true));
-
-/* Get the graphics. */
-$picker_img = Horde::img('colorpicker.png', _("Color Picker"));
-
-?>
-<input type="hidden" name="flag_action" id="flag_action" />
-<input type="hidden" name="flag_data" id="flag_data" />
-<table class="flagmanagement">
- <thead>
-  <tr>
-   <td>Label</td>
-   <td>Icon</td>
-   <td class="colorheader">Color</td>
-  </tr>
- </thead>
- <tbody>
-<?php foreach ($flaglist as $key => $val):
-    $hash = hash('md5', $key);
-    $bgid = 'bg_' . $hash;
-    $color = htmlspecialchars($val['b']);
-    $fgcolor = htmlspecialchars($val['f']);
-    $label = htmlspecialchars($val['l']);
-    $bgstyle = 'background-color:' . $color;
-?>
-  <tr>
-   <td>
-<?php if ($val['t'] == 'imapp'): ?>
-   <input name="<?php echo 'label_' . $hash ?>" value="<?php echo $label ?>" />
-<?php else: ?>
-    <?php echo Horde::label($bgid, $label) ?>
-<?php endif; ?>
-   </td>
-   <td class="flagicon">
-<?php if ($val['t'] == 'imapp'): ?>
-    <div class="msgflags flagUser" style="<?php echo $bgstyle ?>"></div>
-<?php else: ?>
-    <?php echo $val['div'] ?>
-<?php endif; ?>
-   </td>
-   <td>
-    <input size="7" style="<?php echo $bgstyle ?>;color:<?php echo $fgcolor ?>" id="<?php echo $bgid ?>" name="<?php echo $bgid ?>" value="<?php echo $color ?>" />
-    <a class="flagcolorpicker" href="#"><?php echo $picker_img ?></a>
-<?php if (!empty($val['d'])): ?>
-    <a class="flagdelete" href="#"><span class="deleteImg"></span></a>
-<?php endif; ?>
-   </td>
-  </tr>
- </tbody>
-<?php endforeach; ?>
-</table>
-<input id="new_button" type="button" class="button" value="<?php echo _("New Flag") ?>" />
diff --git a/imp/templates/prefs/flags.html b/imp/templates/prefs/flags.html
new file mode 100644 (file)
index 0000000..0fdd4fe
--- /dev/null
@@ -0,0 +1,39 @@
+<input type="hidden" name="flag_action" id="flag_action" />
+<input type="hidden" name="flag_data" id="flag_data" />
+<table class="flagmanagement">
+ <thead>
+  <tr>
+   <td><gettext>Label</gettext></td>
+   <td><gettext>Icon</gettext></td>
+   <td class="colorheader"><gettext>Color</gettext></td>
+  </tr>
+ </thead>
+ <tbody>
+<loop:flags>
+  <tr>
+   <td>
+<if:flags.imapp>
+    <input name="<tag:flags.label_name />" value="<tag:flags.label />" />
+<else:flags.imapp>
+    <tag:flags.label />
+</else:flags.imapp></if:flags.imapp>
+   </td>
+   <td class="flagicon">
+<if:flags.imapp>
+    <div class="msgflags flagUser" style="<tag:flags.icon />"></div>
+<else:flags.imapp>
+    <tag:flags.icon />
+</else:flags.imapp></if:flags.imapp>
+   </td>
+   <td>
+    <input size="7" style="<tag:flags.colorstyle />" id="<tag:flags.colorid />" name="<tag:flags.colorid />" value="<tag:flags.color />" />
+    <a class="flagcolorpicker" href="#"><tag:picker_img /></a>
+<if:flags.flag_del>
+    <a class="flagdelete" href="#"><span class="deleteImg"></span></a>
+</if:flags.flag_del>
+   </td>
+  </tr>
+ </tbody>
+</loop:flags>
+</table>
+<input id="new_button" type="button" class="button" value="<gettext>New Flag</gettext>" />
diff --git a/imp/templates/prefs/initialpage.html b/imp/templates/prefs/initialpage.html
new file mode 100644 (file)
index 0000000..88e6bf8
--- /dev/null
@@ -0,0 +1,15 @@
+<div>
+ <div>
+  <tag:label />
+ </div>
+ <div>
+  <select id="initial_page" name="initial_page">
+<if:nofolder>
+   <option value="INBOX" selected="selected"><gettext>Inbox</gettext></option>
+<else:nofolder>
+   <option value="folders.php"<if:foldersel> selected="selected"</if:foldersel>><gettext>Folder Navigator</gettext></option>
+   <tag:flist />
+</else:nofolder></if:nofolder>
+  </select>
+ </div>
+</div>
diff --git a/imp/templates/prefs/initialpageselect.inc b/imp/templates/prefs/initialpageselect.inc
deleted file mode 100644 (file)
index 1dc7b65..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-if (empty($GLOBALS['conf']['user']['allow_folders'])) {
-    $mailbox_option = '<option value="INBOX" selected="selected">' . _("Inbox") . '</option>';
-} else {
-    $mailbox_selected = $prefs->getValue('initial_page');
-    $mailbox_option = '<option value="folders.php"';
-    if ($mailbox_selected == 'folders.php') {
-        $mailbox_option .= ' selected="selected"';
-    }
-    $mailbox_option .= '>' . _("Folder Navigator") . "</option>\n"
-        . IMP::flistSelect(array('selected' => $mailbox_selected, 'inc_vfolder' => true));
-}
-?>
-<div>
- <div>
-  <?php echo Horde::label('initial_page', _("View or mailbox to display after login:")); ?>
- </div>
- <div>
-  <select id="initial_page" name="initial_page">
-   <?php echo $mailbox_option ?>
-  </select>
- </div>
-</div>
diff --git a/imp/templates/prefs/pgp/import_key.html b/imp/templates/prefs/pgp/import_key.html
deleted file mode 100644 (file)
index 8233115..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<form enctype="multipart/form-data" method="post" name="import_pgp_key" action="<tag:selfurl />">
-<if:broken_mp_form>
-<input type="hidden" name="msie_formdata_is_broken" value="" />
-</if:broken_mp_form>
-<input type="hidden" name="reload" value="<tag:reload />" />
-<input type="hidden" name="actionID" value="<tag:target />" />
-<tag:forminput />
-
-<table border="0" cellspacing="0" cellpadding="2" width="100%">
- <tr>
-  <td class="header leftAlign nowrap"><if:import_public_key><gettext>Import Public PGP Key</gettext></if:import_public_key><if:import_personal_public_key><gettext>Import Personal Public PGP Key</gettext></if:import_personal_public_key><if:import_personal_private_key><gettext>Import Personal Private PGP Key</gettext></if:import_personal_private_key></td>
- </tr>
-
- <tr>
-  <td class="item leftAlign">
-   <table border="0" cellpadding="0" width="100%">
-    <tr>
-     <td class="item leftAlign"><label for="import_key"><strong><if:import_public_key><gettext>Import Public PGP Key Here:</gettext></if:import_public_key><if:import_personal_public_key><gettext>Import Personal Public PGP Key Here:</gettext></if:import_personal_public_key><if:import_personal_private_key><gettext>Import Personal Private PGP Key Here:</gettext></if:import_personal_private_key></strong></label></td>
-    </tr>
-    <tr>
-     <td class="item leftAlign">
-      <textarea id="import_key" name="import_key" rows="6" cols="80" class="fixed"></textarea>
-     </td>
-    </tr>
-   </table>
-  </td>
- </tr>
-
- <tr>
-  <td class="item leftAlign"><font color="red"><strong>--<gettext>OR</gettext>--</strong></font></td>
- </tr>
-
- <tr>
-  <td class="item leftAlign">
-   <table border="0" cellpadding="0" width="100%">
-    <tr>
-     <td class="item leftAlign">
-      <label for="upload_key"><strong><gettext>Upload:</gettext></strong></label>&nbsp;
-      <input id="upload_key" name="upload_key" type="file" size="40" />
-     </td>
-    </tr>
-   </table>
-  </td>
- </tr>
-
- <tr>
-  <td align="center" class="header nowrap">
-   <input type="submit" name="import" class="button" value="<gettext>Import Key</gettext>" />
-   <input type="submit" name="import" class="button" onclick="window.close();" value="<gettext>Cancel</gettext>" />
-  </td>
- </tr>
-</table>
-
-</form>
-</body>
-</html>
diff --git a/imp/templates/prefs/pgp/pgp.html b/imp/templates/prefs/pgp/pgp.html
deleted file mode 100644 (file)
index b80386c..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-<if:pgpactive>
- <div>
-  <input type="checkbox" id="use_pgp" name="use_pgp" checked="checked" />
-  <label for="use_pgp"><gettext>Enable PGP functionality?</gettext></label>
-  <tag:overview-help />
- </div>
- <div>
-  <p>
-   <em class="redText"><gettext>NOTE:</gettext></em> <gettext>PGP support requires popup windows to be used.  If your browser is currently set to disable popup windows, you must change this setting or else the PGP features will not work correctly.</gettext>
-  </p>
- </div>
-<if:attach_pubkey_notlocked>
- <div>
-  <input type="checkbox" id="pgp_attach_pubkey" name="pgp_attach_pubkey"<if:attach_pubkey> checked="checked"</if:attach_pubkey> />
-  <label for="pgp_attach_pubkey"><gettext>Should your PGP public key to be attached to your messages by default?</gettext></label>
-  <tag:attach_pubkey-help />
- </div>
-</if:attach_pubkey_notlocked>
-<if:scan_body_notlocked>
- <div>
-  <input type="checkbox" id="pgp_scan_body" name="pgp_scan_body"<if:scan_body> checked="checked"</if:scan_body> />
-  <label for="pgp_scan_body"><gettext>Should the body of text/plain messages be scanned for PGP data?</gettext></label>
- <tag:scan_body-help />
- </div>
-</if:scan_body_notlocked>
-<if:verify_notlocked>
- <div>
-  <input type="checkbox" id="pgp_verify" name="pgp_verify"<if:pgp_verify> checked="checked"</if:pgp_verify> />
-  <label for="pgp_verify"><gettext>Should PGP signed messages automatically be verified when viewed?</gettext></label>
-  <tag:pgp_verify-help />
- </div>
-</if:verify_notlocked>
-
- <p>
-  <input type="submit" name="save" class="button" onclick="document.prefs.actionID.value='save_options'; return true;" value="<gettext>Save Options</gettext>" />
-  <input id="prefs_return" type="button" name="back" class="button" onclick="document.location.href='<tag:prefsurl />'" value="<gettext>Return to Options</gettext>" />
- </p>
-</div>
-
-<br class="spacer" />
-
-<div class="header">
- <ul><li><tag:manage_pubkey-help /></li></ul>
- <gettext>PGP Public Keyring</gettext>
-</div>
-
-<div class="prefsContainer item">
-<if:empty_pubkey_list>
- <div>
-  <em><gettext>No Keys in Keyring</gettext></em>
- </div>
-<else:empty_pubkey_list>
- <div>
-  <table>
-<loop:pubkey_list>
-   <tr>
-    <td><tag:pubkey_list.name /> (<tag:pubkey_list.email />)</td>
-    <td>&nbsp;&nbsp;[<tag:pubkey_list.view /><gettext>View</gettext></a>]&nbsp;[<tag:pubkey_list.info /><gettext>Details</gettext></a>]&nbsp;[<tag:pubkey_list.delete /><gettext>Delete</gettext></a>]</td>
-   </tr>
-</loop:pubkey_list>
-  </table>
- </div>
-</else:empty_pubkey_list></if:empty_pubkey_list>
-
-<if:no_file_upload>
- <div>
-  <span class="redText"><gettext>Key import is not available. File upload is not enabled on this server.</gettext></span>
- </div>
-<else:no_file_upload>
-<if:no_source>
- <div>
-  <em><gettext>Key import is not available. You have no address book defined to add your contacts.</gettext></em>
- </div>
-<else:no_source>
- <div>
-  <p>
-   <input type="submit" name="save" class="button" onclick="<tag:public_import_url />return false;" value="<gettext>Import Public Key</gettext>" />
-   <tag:import_pubkey-help />
-  </p>
- </div>
-</else:no_source></if:no_source></else:no_file_upload></if:no_file_upload>
-</div>
-
-<br class="spacer" />
-
-<div class="header">
- <ul><li><tag:personalkey-help /></li></ul>
- <gettext>Your PGP Public/Private Keys</gettext>
-</div>
-
-<div class="prefsContainer item">
-<if:secure_check>
- <div>
-  <em><gettext>PGP Personal Keypair support requires a secure web connection.</gettext></em>
- </div>
-<else:secure_check>
- <div>
-<if:has_key>
-  <table>
-   <tr>
-    <td><gettext>Your Public Key:</gettext></td>
-    <td>&nbsp;&nbsp;[<tag:viewpublic /><gettext>View</gettext></a>]&nbsp;[<tag:infopublic /><gettext>Details</gettext></a>]&nbsp;[<tag:sendkey /><gettext>Send Key to Public Keyserver</gettext></a>]</td>
-    <td><tag:personalkey-public-help /></td>
-   </tr>
-   <tr>
-    <td><gettext>Your Private Key:</gettext></td>
-    <td>&nbsp;&nbsp;[<tag:passphrase /></a>]&nbsp;[<tag:viewprivate /><gettext>View</gettext></a>]&nbsp;[<tag:infoprivate /><gettext>Details</gettext></a>]</td>
-    <td><tag:personalkey-private-help /></td>
-   </tr>
-  </table>
- </div>
-
- <p>
-  <input type="submit" name="delete" class="button" onclick="if (confirm('<tag:deletekeypair />')) { document.prefs.actionID.value='delete_key'; return true; } else { return false; }" value="<gettext>Delete Current Keys</gettext>" />
-  <tag:personalkey-delete-help />
- </p>
-<else:has_key>
-  <table>
-   <tr>
-    <td><label for="generate_realname"><gettext>Your Name:</gettext></label></td>
-    <td>&nbsp;&nbsp;<input type="text" id="generate_realname" name="generate_realname" size="30" maxlength="60" value="<tag:fullname />"/></td>
-    <td><tag:personalkey-create-name-help /></td>
-   </tr>
-   <tr>
-    <td><label for="generate_comment"><gettext>Comment:</gettext></label></td>
-    <td>&nbsp;&nbsp;<input type="text" id="generate_comment" name="generate_comment" size="30" maxlength="60" /></td>
-    <td><tag:personalkey-create-comment-help /></td>
-   </tr>
-   <tr>
-    <td><label for="generate_email"><gettext>E-mail Address:</gettext></label></td>
-    <td>&nbsp;&nbsp;<input type="text" id="generate_email" name="generate_email" size="30" maxlength="60" value="<tag:fromaddr />"/></td>
-    <td><tag:personalkey-create-email-help /></td>
-   </tr>
-   <tr>
-    <td><label for="generate_keylength"><gettext>Key Length:</gettext></label></td>
-    <td>&nbsp;
-     <select id="generate_keylength" name="generate_keylength">
-      <option value="1024">1024</option>
-      <option value="2048">2048</option>
-     </select>
-    </td>
-    <td><tag:personalkey-create-keylength-help /></td>
-   </tr>
-   <tr>
-    <td><label for="generate_passphrase1"><gettext>Passphrase:</gettext></label></td>
-    <td>&nbsp;&nbsp;<input type="password" id="generate_passphrase1" name="generate_passphrase1" size="30" maxlength="60" /></td>
-    <td><tag:personalkey-create-passphrase-help /></td>
-   </tr>
-   <tr>
-    <td><label for="generate_passphrase2"><gettext>Passphrase (Again):</gettext></label></td>
-    <td>&nbsp;&nbsp;<input type="password" id="generate_passphrase2" name="generate_passphrase2" size="30" maxlength="60" /></td>
-    <td></td>
-   </tr>
-  </table>
-
-  <p>
-   <input type="submit" name="save" class="button" onclick="if (confirm('<tag:keygen />')) { document.prefs.actionID.value='generate_key';return true; } else { return false; }" value="<gettext>Create Keys</gettext>" />
-<if:no_file_upload><else:no_file_upload>
-   <input type="submit" name="save" class="button" onclick="<tag:personal_import_url />return false;" value="<gettext>Import Keypair</gettext>" />
-</else:no_file_upload></if:no_file_upload>
-   <tag:personalkey-create-actions-help />
-  </p>
-</else:has_key></if:has_key>
- </div>
-</else:secure_check></if:secure_check>
-<else:pgpactive>
-<if:use_pgp_locked>
- <div>
-  <em><gettext>PGP support is disabled on this system.</gettext></em>
- </div>
-<else:use_pgp_locked>
- <div>
-  <input type="checkbox" id="use_pgp" name="use_pgp" />
-  <tag:use_pgp_label />
-  <tag:use_pgp_help />
- </div>
-</else:use_pgp_locked></if:use_pgp_locked>
-
- <p>
-  <input type="submit" name="save" class="button" onclick="document.prefs.actionID.value='save_options'; return true;" value="<gettext>Save Options</gettext>" />
-  <input id="prefs_return" type="button" name="back" class="button" onclick="document.location.href='<tag:prefsurl />'" value="<gettext>Return to Options</gettext>" />
- </p>
-</else:pgpactive></if:pgpactive>
-</div>
-</form>
diff --git a/imp/templates/prefs/pgpprivatekey.html b/imp/templates/prefs/pgpprivatekey.html
new file mode 100644 (file)
index 0000000..188eaea
--- /dev/null
@@ -0,0 +1,125 @@
+<div class="prefsPgpContainer">
+ <div class="prefsPgpHeader">
+  <h3><gettext>Your PGP Public/Private Keys</gettext> <tag:personalkey-help /></h3>
+ </div>
+
+<if:notsecure>
+ <div>
+  <em class="prefsPgpWarning"><gettext>PGP Personal Keypair support requires a secure web connection.</gettext></em>
+ </div>
+<else:notsecure>
+<if:has_key>
+ <div>
+  <table>
+   <tr>
+    <td>
+     <gettext>Your Public Key:</gettext>
+    </td>
+    <td>
+     [<tag:viewpublic /><gettext>View</gettext></a>] [<tag:infopublic /><gettext>Details</gettext></a>] [<tag:sendkey /><gettext>Send Key to Public Keyserver</gettext></a>]
+    </td>
+    <td>
+     <tag:personalkey-public-help />
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <gettext>Your Private Key:</gettext>
+    </td>
+    <td>
+     [<tag:passphrase /></a>] [<tag:viewprivate /><gettext>View</gettext></a>] [<tag:infoprivate /><gettext>Details</gettext></a>]
+    </td>
+    <td>
+     <tag:personalkey-private-help />
+    </td>
+   </tr>
+  </table>
+ </div>
+
+ <p>
+  <input type="submit" name="delete_pgp_privkey" class="button" onclick="confirm('<tag:deletekeypair />')" value="<gettext>Delete Current Keys</gettext>" />
+  <tag:personalkey-delete-help />
+ </p>
+<else:has_key>
+ <div>
+  <table>
+   <tr>
+    <td>
+     <label for="generate_realname"><gettext>Your Name:</gettext></label>
+    </td>
+    <td>
+     <input type="text" id="generate_realname" name="generate_realname" size="30" maxlength="60" value="<tag:fullname />"/>
+    </td>
+    <td>
+     <tag:personalkey-create-name-help />
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <label for="generate_comment"><gettext>Comment:</gettext></label>
+    </td>
+    <td>
+     <input type="text" id="generate_comment" name="generate_comment" size="30" maxlength="60" />
+    </td>
+    <td>
+     <tag:personalkey-create-comment-help />
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <label for="generate_email"><gettext>E-mail Address:</gettext></label>
+    </td>
+    <td>
+     <input type="text" id="generate_email" name="generate_email" size="30" maxlength="60" value="<tag:fromaddr />"/>
+    </td>
+    <td>
+     <tag:personalkey-create-email-help />
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <label for="generate_keylength"><gettext>Key Length:</gettext></label>
+    </td>
+    <td>
+     <select id="generate_keylength" name="generate_keylength">
+      <option value="1024">1024</option>
+      <option value="2048">2048</option>
+     </select>
+    </td>
+    <td>
+     <tag:personalkey-create-keylength-help />
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <label for="generate_passphrase1"><gettext>Passphrase:</gettext></label>
+    </td>
+    <td>
+     <input type="password" id="generate_passphrase1" name="generate_passphrase1" size="30" maxlength="60" />
+    </td>
+    <td>
+     <tag:personalkey-create-passphrase-help />
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <label for="generate_passphrase2"><gettext>Passphrase (Again):</gettext></label>
+    </td>
+    <td>
+     <input type="password" id="generate_passphrase2" name="generate_passphrase2" size="30" maxlength="60" />
+    </td>
+    <td></td>
+   </tr>
+  </table>
+
+  <p>
+   <input type="submit" name="create_pgp_key" class="button" onclick="confirm('<tag:keygen />')" value="<gettext>Create Keys</gettext>" />
+<if:import_url>
+   <input type="submit" name="save" class="button" onclick="<tag:import_url />return false;" value="<gettext>Import Keypair</gettext>" />
+</if:import_url>
+   <tag:personalkey-create-actions-help />
+  </p>
+ </div>
+</else:has_key></if:has_key>
+</else:notsecure></if:notsecure>
+</div>
diff --git a/imp/templates/prefs/pgppublickey.html b/imp/templates/prefs/pgppublickey.html
new file mode 100644 (file)
index 0000000..097fc81
--- /dev/null
@@ -0,0 +1,41 @@
+<div class="prefsPgpContainer">
+ <div class="prefsPgpHeader">
+   <h3><gettext>PGP Public Keyring</gettext> <tag:manage_pubkey-help /></h3>
+ </div>
+
+ <div>
+  <div>
+<if:pubkey_list>
+   <table>
+<loop:pubkey_list>
+    <tr>
+     <td><tag:pubkey_list.name /> (<tag:pubkey_list.email />)</td>
+     <td>[<tag:pubkey_list.view /><gettext>View</gettext></a>] [<tag:pubkey_list.info /><gettext>Details</gettext></a>] [<tag:pubkey_list.delete /><gettext>Delete</gettext></a>]</td>
+    </tr>
+</loop:pubkey_list>
+   </table>
+<else:pubkey_list>
+   <em><gettext>No Keys in Keyring</gettext></em>
+</else:pubkey_list></if:pubkey_list>
+  </div>
+
+<if:import_url>
+<if:no_source>
+  <div>
+   <em><gettext>Key import is not available. You have no address book defined to add your contacts.</gettext></em>
+  </div>
+<else:no_source>
+  <div>
+   <p>
+    <input type="submit" name="save" class="button" onclick="<tag:import_url />return false;" value="<gettext>Import Public Key</gettext>" />
+   <tag:import_pubkey-help />
+   </p>
+  </div>
+ </else:no_source></if:no_source>
+<else:import_url>
+  <div>
+   <div class="prefsPgpWarning"><gettext>Key import is not available. File upload is not enabled on this server.</gettext></div>
+  </div>
+</else:import_url></if:import_url>
+ </div>
+</div>
diff --git a/imp/templates/prefs/sentmail.html b/imp/templates/prefs/sentmail.html
new file mode 100644 (file)
index 0000000..f40bca4
--- /dev/null
@@ -0,0 +1,13 @@
+<div>
+ <div>
+  <tag:label />
+ </div>
+ <div>
+  <input type="hidden" name="sent_mail_new" id="sent_mail_new" value="" />
+  <select name="sent_mail_folder" id="sent_mail_folder">
+   <option value=""><gettext>None</gettext></option>
+   <option value="-1" selected="selected"><gettext>Use Default Value</gettext></option>
+   <tag:flist />
+  </select>
+ </div>
+</div>
diff --git a/imp/templates/prefs/sentmailselect.inc b/imp/templates/prefs/sentmailselect.inc
deleted file mode 100644 (file)
index 2a438dc..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<div>
- <div>
-  <?php echo Horde::label('sent_mail_folder', _("Sent mail folder:")) ?>
- </div>
- <div>
-  <input type="hidden" name="sent_mail_new" id="sent_mail_new" value="" />
-  <select name="sent_mail_folder" id="sent_mail_folder">
-   <option value=""><?php echo _("None") ?></option>
-   <option value="-1" selected="selected"><?php echo _("Use Default Value") ?></option>
-   <?php echo IMP::flistSelect(array('heading' => _("Create a new sent mail folder"), 'filter' => array('INBOX'))) ?>
-  </select>
- </div>
-</div>
diff --git a/imp/templates/prefs/smime/import_key.html b/imp/templates/prefs/smime/import_key.html
deleted file mode 100644 (file)
index cdd7b1f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-<form enctype="multipart/form-data" method="post" name="import_pgp_key" action="<tag:selfurl />">
-<if:broken_mp_form>
-<input type="hidden" name="msie_formdata_is_broken" value="" />
-</if:broken_mp_form>
-<input type="hidden" name="reload" value="<tag:reload />" />
-<input type="hidden" name="actionID" value="<tag:target />" />
-<tag:forminput />
-
-<table cellspacing="0" width="100%">
- <tr>
-  <td class="header leftAlign nowrap"<if:import_personal_certs> colspan="2"</if:import_personal_certs>><if:import_public_key><gettext>Import Public S/MIME Key</gettext></if:import_public_key><if:import_personal_certs><gettext>Import Personal S/MIME Certificates</gettext></if:import_personal_certs></td>
- </tr>
-
-<if:import_public_key>
- <tr>
-  <td class="item leftAlign">
-   <table width="100%">
-    <tr>
-     <td class="item leftAlign"><label for="import_key"><strong><gettext>Insert Certificate Here:</gettext></strong></label></td>
-    </tr>
-    <tr>
-     <td class="item leftAlign">
-      <textarea id="import_key" name="import_key" rows="6" cols="80" class="fixed"></textarea>
-     </td>
-    </tr>
-   </table>
-  </td>
- </tr>
-
- <tr>
-  <td class="item leftAlign"><font color="red"><strong>--<gettext>OR</gettext>--</strong></font></td>
- </tr>
-</if:import_public_key>
-
- <tr>
-  <td class="item leftAlign"<if:import_personal_certs> colspan="2"</if:import_personal_certs>>
-   <table width="100%">
-    <tr>
-     <td class="item leftAlign">
-      <label for="upload_key"><strong><gettext>Upload:</gettext></strong></label>&nbsp;
-      <input id="upload_key" name="upload_key" type="file" size="40" />
-     </td>
-    </tr>
-   </table>
-  </td>
- </tr>
-
-<if:import_personal_certs>
- <tr>
-  <td class="item leftAlign" colspan="2">
-   <table width="100%">
-    <tr>
-     <td class="item leftAlign">
-      <label for="upload_key_pass"><strong><gettext>Password:</gettext></strong></label>&nbsp;<input id="upload_key_pass" name="upload_key_pass" type="password" size="30" />
-     </td>
-    </tr>
-    <tr>
-     <td class="item leftAlign">
-      <label for="upload_key_pk_pass"><strong><gettext>Private Key Password:</gettext></strong></label>&nbsp;<input id="upload_key_pk_pass" name="upload_key_pk_pass" type="password" size="30" />
-     </td>
-    </tr>
-   </table>
-  </td>
- </tr>
-</if:import_personal_certs>
-
- <tr>
-  <td align="center" class="header nowrap">
-   <input type="submit" name="import" class="button" value="<gettext>Import Key</gettext>" />
-   <input type="submit" name="import" class="button" onclick="window.close();" value="<gettext>Cancel</gettext>" />
-  </td>
- </tr>
-</table>
-
-</form>
-</body>
-</html>
diff --git a/imp/templates/prefs/smime/smime.html b/imp/templates/prefs/smime/smime.html
deleted file mode 100644 (file)
index b3206c9..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<if:smimeactive>
- <div>
-  <input type="checkbox" id="use_smime" name="use_smime" checked="checked" />
-  <label for="use_smime"><gettext>Enable S/MIME functionality?</gettext></label>
-  <tag:use_smime_help />
- </div>
- <div>
-  <p>
-   <em class="redText"><gettext>NOTE:</gettext></em> <gettext>S/MIME support requires popup windows to be used.  If your browser is currently set to disable popup windows, you must change this setting or else the S/MIME features will not work correctly.</gettext>
-  </p>
- </div>
-<if:verify_notlocked>
- <div>
-  <input type="checkbox" id="smime_verify" name="smime_verify"<if:smime_verify> checked="checked"</if:smime_verify> />
-  <label for="smime_verify"><gettext>Should S/MIME signed messages automatically be verified when viewed?</gettext></label>
-  <tag:smime_verify-help />
- </div>
-</if:verify_notlocked>
-
- <p>
-  <input type="submit" name="save" class="button" onclick="document.prefs.actionID.value='save_options'; return true;" value="<gettext>Save Options</gettext>" />
-  <input id="prefs_return" type="button" name="back" class="button" onclick="document.location.href='<tag:prefsurl />'" value="<gettext>Return to Options</gettext>" />
- </p>
-</div>
-
-<br class="spacer" />
-
-<div class="header">
- <ul><li><tag:manage_pubkey-help /></li></ul>
- <gettext>S/MIME Public Keyring</gettext>
-</div>
-
-<div class="prefsContainer item">
- <div>
-<if:empty_pubkey_list>
-  <em><gettext>No Keys in Keyring</gettext></em>
-<else:empty_pubkey_list>
-  <table>
-<loop:pubkey_list>
-   <tr>
-    <td><tag:pubkey_list.name /> (<tag:pubkey_list.email />)</td>
-    <td>&nbsp;&nbsp;[<tag:pubkey_list.view /><gettext>View</gettext></a>]&nbsp;[<tag:pubkey_list.info /><gettext>Details</gettext></a>]&nbsp;[<tag:pubkey_list.delete /><gettext>Delete</gettext></a>]</td>
-   </tr>
-</loop:pubkey_list>
-  </table>
-</else:empty_pubkey_list></if:empty_pubkey_list>
- </div>
-
- <div>
-<if:no_file_upload>
-  <em class="redText"><gettext>Key import is not available. File upload is not enabled on this server.</gettext></em>
-<else:no_file_upload>
-<if:no_source>
-  <em><gettext>Key import is not available. You have no address book defined to add your contacts.</gettext></em>
-<else:no_source>
-  <p>
-   <input type="submit" name="save" class="button" onclick="<tag:public_import_url />return false;" value="<gettext>Import Public Key</gettext>" />
-   <tag:import_pubkey-help />
-  </p>
-</else:no_source></if:no_source></else:no_file_upload></if:no_file_upload>
- </div>
-</div>
-
-<br class="spacer" />
-
-<div class="header">
- <ul><li><tag:personalkey-help /></li></ul>
- <gettext>Your S/MIME Public/Private Certificate</gettext>
-</div>
-
-<div class="prefsContainer item">
-<if:secure_check>
-<if:has_key>
- <div>
-  <table>
-   <tr>
-    <td><gettext>Your Public Key:</gettext></td>
-    <td>&nbsp;&nbsp;[<tag:viewpublic /><gettext>View</gettext></a>]&nbsp;[<tag:infopublic /><gettext>Details</gettext></a>]</td>
-   </tr>
-   <tr>
-    <td><gettext>Your Private Key:</gettext></td>
-    <td>&nbsp;&nbsp;[<tag:passphrase /></a>]&nbsp;[<tag:viewprivate /><gettext>View</gettext></a>]</td>
-   </tr>
-  </table>
- </div>
-
- <p>
-  <input type="submit" name="delete" class="button" onclick="if (confirm('<tag:deletekeypair />')) { document.prefs.actionID.value='delete_key'; return true; } else { return false; }" value="<gettext>Delete Current Keys</gettext>" />
-  <tag:personalkey-delete-help />
- </p>
-<else:has_key>
-<if:no_file_upload>
- <div>
-  <em class="redText"><gettext>Certificate import is not available. File upload is not enabled on this server.</gettext></em>
- </div>
-<else:no_file_upload>
- <div>
-  <em class="redText"><gettext>No certificate available.</gettext></em>
- </div>
- <p>
-  <input type="submit" name="save" class="button" onclick="<tag:personal_import_url />return false;" value="<gettext>Import Keypair</gettext>" />
-  <tag:import-cert-help />
- </p>
-</else:no_file_upload></if:no_file_upload>
-</else:has_key></if:has_key>
-<else:secure_check>
- <div>
-  <em><gettext>S/MIME Personal Keypair support requires a secure web connection.</gettext></em>
- </div>
-</else:secure_check></if:secure_check>
-<else:smimeactive>
-<if:use_smime_locked>
- <div>
-  <em><gettext>S/MIME support is disabled on this system.</gettext></em>
- </div>
-<else:use_smime_locked>
- <div>
-  <input type="checkbox" id="use_smime" name="use_smime" />
-  <tag:use_smime_label />
-  <tag:use_smime_help />
- </div>
-</else:use_smime_locked></if:use_smime_locked>
-
- <p>
-  <input type="submit" name="save" class="button" onclick="document.prefs.actionID.value='save_options'; return true;" value="<gettext>Save Options</gettext>" />
-  <input id="prefs_return" type="button" name="back" class="button" onclick="document.location.href='<tag:prefsurl />'" value="<gettext>Return to Options</gettext>" />
- </p>
-</else:smimeactive></if:smimeactive>
-</div>
-</form>
diff --git a/imp/templates/prefs/smimeprivatekey.html b/imp/templates/prefs/smimeprivatekey.html
new file mode 100644 (file)
index 0000000..790ad67
--- /dev/null
@@ -0,0 +1,48 @@
+<div class="prefsSmimeContainer">
+ <div class="prefsSmimeHeader">
+  <h3><gettext>Your S/MIME Public/Private Certificate</gettext> <tag:personalkey-help /></h3>
+ </div>
+
+<if:notsecure>
+ <div>
+  <em class="prefsSmimeWarning"><gettext>S/MIME Personal Certificate support requires a secure web connection.</gettext></em>
+ </div>
+<else:notsecure>
+<if:has_key>
+ <div>
+  <table>
+   <tr>
+    <td>
+     <gettext>Your Public Certificate:</gettext>
+    </td>
+    <td>
+     [<tag:viewpublic /><gettext>View</gettext></a>] [<tag:infopublic /><gettext>Details</gettext></a>]
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <gettext>Your Private Certificate:</gettext>
+    </td>
+    <td>
+     [<tag:passphrase /></a>] [<tag:viewprivate /><gettext>View</gettext></a>]
+    </td>
+   </tr>
+  </table>
+ </div>
+
+ <p>
+  <input type="submit" name="delete_smime_personal" class="button" onclick="confirm('<tag:deletekeypair />')" value="<gettext>Delete Personal Certificate</gettext>" />
+  <tag:personalkey-delete-help />
+ </p>
+<else:has_key>
+<if:import_url>
+ <div>
+  <p>
+   <input type="submit" name="save" class="button" onclick="<tag:import_url />return false;" value="<gettext>Import Personal Certificate</gettext>" />
+   <tag:import-cert-help />
+  </p>
+ </div>
+</if:import_url>
+</else:has_key></if:has_key>
+</else:notsecure></if:notsecure>
+</div>
diff --git a/imp/templates/prefs/smimepublickey.html b/imp/templates/prefs/smimepublickey.html
new file mode 100644 (file)
index 0000000..bce9dc6
--- /dev/null
@@ -0,0 +1,41 @@
+<div class="prefsSmimeContainer">
+ <div class="prefsSmimeHeader">
+   <h3><gettext>S/MIME Public Keyring</gettext> <tag:manage_pubkey-help /></h3>
+ </div>
+
+ <div>
+  <div>
+<if:pubkey_list>
+   <table>
+<loop:pubkey_list>
+    <tr>
+     <td><tag:pubkey_list.name /> (<tag:pubkey_list.email />)</td>
+     <td>[<tag:pubkey_list.view /><gettext>View</gettext></a>] [<tag:pubkey_list.info /><gettext>Details</gettext></a>] [<tag:pubkey_list.delete /><gettext>Delete</gettext></a>]</td>
+    </tr>
+</loop:pubkey_list>
+   </table>
+<else:pubkey_list>
+   <em><gettext>No Keys in Keyring</gettext></em>
+</else:pubkey_list></if:pubkey_list>
+  </div>
+
+<if:import_url>
+<if:no_source>
+  <div>
+   <em><gettext>Key import is not available. You have no address book defined to add your contacts.</gettext></em>
+  </div>
+<else:no_source>
+  <div>
+   <p>
+    <input type="submit" name="save" class="button" onclick="<tag:import_url />return false;" value="<gettext>Import Public Key</gettext>" />
+   <tag:import_pubkey-help />
+   </p>
+  </div>
+ </else:no_source></if:no_source>
+<else:import_url>
+  <div>
+   <div class="prefsSmimeWarning"><gettext>Key import is not available. File upload is not enabled on this server.</gettext></div>
+  </div>
+</else:import_url></if:import_url>
+ </div>
+</div>
diff --git a/imp/templates/prefs/sound.html b/imp/templates/prefs/sound.html
new file mode 100644 (file)
index 0000000..4356458
--- /dev/null
@@ -0,0 +1,20 @@
+<div>
+ <p><gettext>Play a sound on new mail? Although most browsers support embedded sound files, some may require a plugin.</gettext></p>
+ <ul class="sound-list">
+  <li>
+   <label>
+    <input type="radio" name="nav_audio" value=""<if:nav_audio><else:nav_audio> checked="checked"</else:nav_audio></if:nav_audio> />
+    <gettext>No Sound</gettext>
+   </label>
+  </li>
+<loop:sounds>
+  <li>
+   <label>
+    <input type="radio" name="nav_audio" value="<tag:sounds.v />"<if:sounds.c> checked="checked"</if:sounds.c> />
+    <tag:sounds.l />
+   </label>
+   <embed autostart="false" src="<tag:sounds.s />" />
+  </li>
+</loop:sounds>
+ </ul>
+</div>
diff --git a/imp/templates/prefs/soundselect.inc b/imp/templates/prefs/soundselect.inc
deleted file mode 100644 (file)
index b05f656..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-    $nav_audio = $prefs->getValue('nav_audio')
-?>
-<div>
- <p><?php echo _("Play a sound on new mail? Although most browsers support embedded sound files, some may require a plugin.") ?></p>
- <ul class="sound-list">
-  <li>
-   <label>
-    <input type="radio" name="nav_audio" value=""<?php if (!$nav_audio) echo ' checked="checked"' ?> />
-    <?php echo _("No Sound") ?>
-   </label>
-  </li>
-<?php foreach (Horde_Themes::soundList() as $key => $val): ?>
-  <li>
-   <label>
-    <input type="radio" name="nav_audio" value="<?php echo htmlspecialchars($key) ?>"<?php if ($nav_audio == $key) echo ' checked="checked"' ?> />
-    <?php echo htmlspecialchars($key) ?>
-   </label>
-   <embed autostart="false" src="<?php echo htmlspecialchars($val->uri) ?>" />
-  </li>
-<?php endforeach; ?>
- </ul>
-</div>
diff --git a/imp/templates/prefs/sourceselect.inc b/imp/templates/prefs/sourceselect.inc
deleted file mode 100644 (file)
index 7806db3..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php $cache = IMP_Application::$prefsCache['sourceselect']; ?>
-<?php if (!empty($cache['readSelect']) || !empty($cache['prefSelect'])): ?>
-<div>
- <input type="hidden" name="search_sources" id="search_sources" value="<?php echo implode("\t", $cache['search']['sources']) ?>" />
-<?php if (count($cache['readable']) > 1): ?>
- <p><?php echo _("Choose the order of address books to search when expanding addresses.") ?></p>
- <table>
-  <tr>
-   <td>
-    <label for="unselected_search_sources" class="hidden"><?php echo _("Available Address books:") ?></label>
-    <select id="unselected_search_sources" name="unselected_search_sources" id="unselected_search_sources" multiple="multiple" size="5" style="width:20em">
-     <option value=""><?php echo _("Available Address books:") ?></option>
-<?php foreach ($cache['readSelect'] as $val): ?>
-     <option value="<?php echo $val ?>"><?php echo $cache['readable'][$val] ?></option>
-<?php endforeach; ?>
-    </select>
-   </td>
-   <td>
-    <a href="#" id="addsource"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'lhand.png' : 'rhand.png', _("Add source")) ?></a>
-    <br />
-    <a href="#" id="removesource"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'rhand.png' : 'lhand.png', _("Remove source")) ?></a>
-   </td>
-   <td>
-    <label for="selected_search_sources" class="hidden"><?php echo _("Selected Address books:") ?></label>
-    <select name="selected_search_sources" multiple="multiple" size="5" style="width:20em" id="selected_search_sources">
-     <option value=""><?php echo _("Selected Address books:") ?></option>
-<?php foreach ($cache['prefSelect'] as $key => $val): ?>
-     <option value="<?php echo $key ?>"><?php echo $val ?></option>
-<?php endforeach; ?>
-    </select>
-   </td>
-   <td>
-    <a href="#" id="moveup"><?php echo Horde::img('nav/up.png', _("Move up")) ?></a>
-    <br />
-    <a href="#" id="movedown"><?php echo Horde::img('nav/down.png', _("Move down")) ?></a>
-   </td>
-  </tr>
- </table>
-
- <p><?php echo _("Click on one of your selected address books and then select all fields to search.") ?></p>
-<?php else: ?>
- <p><?php echo _("Select all fields to search when expanding addresses.") ?></p>
-<?php endif; ?>
-
- <div><?php echo _("To select multiple fields, hold down the Control (PC) or Command (Mac) while clicking.") ?></div>
- <input type="hidden" name="search_fields_string" id="search_fields_string" />
- <table>
-  <tr>
-   <td>
-    <label for="search_fields" class="hidden"><?php echo _("Fields to search") ?></label>
-    <select id="search_fields" name="search_fields" multiple="multiple" size="5" style="width:20em">
-     <option><?php echo str_repeat('&nbsp;', 50) ?></option>
-    </select>
-   </td>
-  </tr>
- </table>
-<?php endif; ?>
-
-<?php if (!empty($cache['writeSelect'])): ?>
- <div><?php echo _("Choose the address book to use when adding addresses.") ?></div>
- <label for="add_source" class="hidden"><?php echo _("Address book to add addresses to") ?></label>
- <select id="add_source" name="add_source">
-  <option value=""><?php echo _("None") ?></option>
-<?php foreach ($cache['writeSelect'] as $val): ?>
-  <option value="<?php echo $val['val'] ?>"<?php if ($val['sel']) echo ' selected="selected"'; ?>><?php echo $val['name'] ?></option>
-<?php endforeach; ?>
- </select>
-<?php endif; ?>
-</div>
diff --git a/imp/templates/prefs/spam.html b/imp/templates/prefs/spam.html
new file mode 100644 (file)
index 0000000..963ea08
--- /dev/null
@@ -0,0 +1,12 @@
+<div>
+ <div>
+  <tag:label />
+ </div>
+ <div>
+  <input type="hidden" name="spam_new" id="spam_new" value="" />
+  <select id="spam" name="spam">
+   <option value="<tag:nofolder />"><gettext>None</gettext></option>
+   <tag:flist />
+  </select>
+ </div>
+</div>
diff --git a/imp/templates/prefs/spamselect.inc b/imp/templates/prefs/spamselect.inc
deleted file mode 100644 (file)
index 9cfd315..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<div>
- <div>
-  <?php echo Horde::label('spam', _("Spam folder:")) ?>
- </div>
- <div>
-  <input type="hidden" name="spam_new" id="spam_new" value="" />
-  <select id="spam" name="spam">
-   <option value="<?php echo IMP::PREF_NO_FOLDER ?>"><?php echo _("None") ?></option>
-   <?php echo IMP::flistSelect(array('heading' => _("Create a new Spam folder"), 'filter' => array('INBOX'), 'selected' => IMP::folderPref($prefs->getValue('spam_folder'), true), 'new_folder' => true)) ?>
-  </select>
- </div>
-</div>
diff --git a/imp/templates/prefs/stationery.html b/imp/templates/prefs/stationery.html
new file mode 100644 (file)
index 0000000..a03a0e9
--- /dev/null
@@ -0,0 +1,51 @@
+<input type="hidden" name="last_type" value="<tag:last_type />" />
+
+<div>
+ <label for="stationery" class="hidden"><gettext>Stationery</gettext></label>
+ <select id="stationery" name="stationery" onchange="$('edit').click()">
+  <option value=""><gettext>Create new stationery</gettext></option>
+<loop:slist>
+  <option value="<tag:slist.val />"<if:slist.selected> selected="selected"</if:slist.selected>><tag:slist.text /></option>
+</loop:slist>
+ </select>
+ <input type="submit" id="edit" name="edit" class="button" value="<gettext>Edit</gettext>" />
+</div>
+
+<div>
+ <tag:name_label />
+</div>
+
+<div>
+ <input type="text" name="name" id="name" value="<tag:name />" />
+</div>
+
+<div>
+ <tag:type_label />
+</div>
+
+<div>
+ <select name="type" id="type" onchange="$('switch_type').click()">
+  <option value="plain"<if:plain> selected="selected"</if:plain>><gettext>Text</gettext></option>
+  <option value="html"<if:html> selected="selected"</if:html>><gettext>HTML</gettext></option>
+ </select>
+ <input type="submit" id="switch_type" name="switch_type" class="button" value="<gettext>Switch</gettext>" />
+</div>
+
+<div>
+ <tag:content_label />
+</div>
+
+<div>
+ <textarea name="content" id="content" rows="15" cols="80" class="fixed"><tag:content /></textarea>
+</div>
+
+<p>
+ <em><gettext>You can use the following placeholders in the stationery text: %c for the current message content; %s for the signature.</gettext></em>
+</p>
+
+<div>
+ <input type="submit" name="save" class="button" value="<gettext>Save Stationery</gettext>" />
+<if:selected>
+ <input type="submit" name="delete" class="button" value="<gettext>Delete Stationery</gettext>" />
+</if:selected>
+</div>
diff --git a/imp/templates/prefs/stationery/stationery.html b/imp/templates/prefs/stationery/stationery.html
deleted file mode 100644 (file)
index e493005..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<form method="post" name="prefs" action="<tag:action />">
-<tag:forminput />
-<input type="hidden" name="actionID" value="update" />
-<input type="hidden" name="group" value="compose" />
-<input type="hidden" name="app" value="imp" />
-
-<div class="header">
- <tag:navcell /> <gettext>Stationery</gettext>
-</div>
-
-<p class="item">
-<label for="stationery" class="hidden"><gettext>Stationery</gettext></label>
-<select id="stationery" name="stationery" onchange="document.prefs.edit.click()">
- <option value=""><gettext>Create new stationery</gettext></option>
-<loop:slist>
- <option value="<tag:slist.val />"<if:slist.selected> selected="selected"</if:slist.selected>><tag:slist.text /></option>
-</loop:slist>
-</select>
-<input type="submit" name="edit" class="button" value="<gettext>Edit</gettext>" />
-
-<br />
-
-<input type="hidden" name="last_type" value="<tag:last_type />" />
-<tag:name_label />
-<br />
-<input type="text" name="name" id="name" value="<tag:name />" />
-<br />
-<tag:type_label />
-<br />
-<select name="type" id="type" onchange="if (document.prefs.onsubmit) document.prefs.onsubmit(); document.prefs.submit()">
- <option value="plain"<if:plain> selected="selected"</if:plain>><gettext>Text</gettext></option>
- <option value="html"<if:html> selected="selected"</if:html>><gettext>HTML</gettext></option>
-</select>
-<br />
-<tag:content_label />
-<br />
-<textarea name="content" id="content" rows="15" cols="80" class="fixed"><tag:content /></textarea>
-<br />
-<em><gettext>You can use the following placeholders in the stationery text: %c for the current message content; %s for the signature.</gettext></em>
-</p>
-
-<input type="submit" name="save" class="button" value="<gettext>Save Stationery</gettext>" />&nbsp;&nbsp;
-<if:selected>
-<input type="submit" name="delete" class="button" value="<gettext>Delete Stationery</gettext>" />&nbsp;&nbsp;
-</if:selected>
-
-<input type="button" name="back" class="button" onclick="document.location.href='<tag:button_href />'" value="<tag:button_val />" />
-
-</form>
diff --git a/imp/templates/prefs/trash.html b/imp/templates/prefs/trash.html
new file mode 100644 (file)
index 0000000..b78db8c
--- /dev/null
@@ -0,0 +1,13 @@
+<div>
+ <div>
+  <tag:label />
+ </div>
+ <div>
+  <input type="hidden" name="trash_new" id="trash_new" value="" />
+  <select id="trash" name="trash">
+   <option value="<tag:nofolder />"><gettext>None</gettext></option>
+   <option value="<tag:vtrash />"<if:vtrash_select> selected="selected"</if:vtrash_select>><gettext>Use Virtual Trash</gettext></option>
+   <tag:flist />
+  </select>
+ </div>
+</div>
diff --git a/imp/templates/prefs/trashselect.inc b/imp/templates/prefs/trashselect.inc
deleted file mode 100644 (file)
index 5b67ef2..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<div>
- <div>
-  <?php echo Horde::label('trash', _("Trash folder:")) ?>
- </div>
- <div>
-  <input type="hidden" name="trash_new" id="trash_new" value="" />
-  <select id="trash" name="trash">
-<?php
-    $use_vtrash = $prefs->getValue('use_vtrash');
-    echo '<option value="' . IMP::PREF_NO_FOLDER . '">' . _("None") . '</option>' .
-    '<option value="' . IMP::PREF_VTRASH . '"' . (($use_vtrash) ? ' selected="selected"' : '') . '>' . _("Use Virtual Trash") . '</option>' .
-    IMP::flistSelect(array('heading' => _("Create a new trash folder"), 'filter' => array('INBOX'), 'selected' => ($use_vtrash ? null : IMP::folderPref($prefs->getValue('trash_folder'), true)), 'new_folder' => true));
-?>
-  </select>
- </div>
-</div>
diff --git a/imp/templates/smime/import_key.html b/imp/templates/smime/import_key.html
new file mode 100644 (file)
index 0000000..cdd7b1f
--- /dev/null
@@ -0,0 +1,77 @@
+<form enctype="multipart/form-data" method="post" name="import_pgp_key" action="<tag:selfurl />">
+<if:broken_mp_form>
+<input type="hidden" name="msie_formdata_is_broken" value="" />
+</if:broken_mp_form>
+<input type="hidden" name="reload" value="<tag:reload />" />
+<input type="hidden" name="actionID" value="<tag:target />" />
+<tag:forminput />
+
+<table cellspacing="0" width="100%">
+ <tr>
+  <td class="header leftAlign nowrap"<if:import_personal_certs> colspan="2"</if:import_personal_certs>><if:import_public_key><gettext>Import Public S/MIME Key</gettext></if:import_public_key><if:import_personal_certs><gettext>Import Personal S/MIME Certificates</gettext></if:import_personal_certs></td>
+ </tr>
+
+<if:import_public_key>
+ <tr>
+  <td class="item leftAlign">
+   <table width="100%">
+    <tr>
+     <td class="item leftAlign"><label for="import_key"><strong><gettext>Insert Certificate Here:</gettext></strong></label></td>
+    </tr>
+    <tr>
+     <td class="item leftAlign">
+      <textarea id="import_key" name="import_key" rows="6" cols="80" class="fixed"></textarea>
+     </td>
+    </tr>
+   </table>
+  </td>
+ </tr>
+
+ <tr>
+  <td class="item leftAlign"><font color="red"><strong>--<gettext>OR</gettext>--</strong></font></td>
+ </tr>
+</if:import_public_key>
+
+ <tr>
+  <td class="item leftAlign"<if:import_personal_certs> colspan="2"</if:import_personal_certs>>
+   <table width="100%">
+    <tr>
+     <td class="item leftAlign">
+      <label for="upload_key"><strong><gettext>Upload:</gettext></strong></label>&nbsp;
+      <input id="upload_key" name="upload_key" type="file" size="40" />
+     </td>
+    </tr>
+   </table>
+  </td>
+ </tr>
+
+<if:import_personal_certs>
+ <tr>
+  <td class="item leftAlign" colspan="2">
+   <table width="100%">
+    <tr>
+     <td class="item leftAlign">
+      <label for="upload_key_pass"><strong><gettext>Password:</gettext></strong></label>&nbsp;<input id="upload_key_pass" name="upload_key_pass" type="password" size="30" />
+     </td>
+    </tr>
+    <tr>
+     <td class="item leftAlign">
+      <label for="upload_key_pk_pass"><strong><gettext>Private Key Password:</gettext></strong></label>&nbsp;<input id="upload_key_pk_pass" name="upload_key_pk_pass" type="password" size="30" />
+     </td>
+    </tr>
+   </table>
+  </td>
+ </tr>
+</if:import_personal_certs>
+
+ <tr>
+  <td align="center" class="header nowrap">
+   <input type="submit" name="import" class="button" value="<gettext>Import Key</gettext>" />
+   <input type="submit" name="import" class="button" onclick="window.close();" value="<gettext>Cancel</gettext>" />
+  </td>
+ </tr>
+</table>
+
+</form>
+</body>
+</html>
index cc26262..8b69c64 100644 (file)
@@ -226,6 +226,11 @@ span.trashImg {
     background-image: url("graphics/folders/trash.png");
 }
 
+.folderunsub {
+    background: #bbb;
+    font-style: italic;
+}
+
 /* Style for div that fixes KHTML browsers. */
 .ohide {
     overflow: hidden;
@@ -364,15 +369,23 @@ table.accountsmanagement td.noneconfigured {
     font-style: italic;
 }
 
-/* PGP & S/MIME prefs styles. */
-.redText {
+/* Prefs styles. */
+.prefsPgpContainer, .prefsSmimeContainer {
+    border: 1px solid black;
+    margin: 5px 0;
+    padding: 4px;
+    -moz-border-radius: 4px;
+    -webkit-border-radius: 4px;
+}
+.prefsPgpHeader, .prefsSmimeHeader {
+    margin-bottom: 5px;
+}
+.prefsPgpWarning, .prefsSmimeWarning {
     color: red;
+    padding: 5px 10px;
 }
 
-.folderunsub {
-    background: #bbb;
-    font-style: italic;
-}
+/* Quota styles. */
 .quotawarn {
     color: #000;
     background: yellow;
index 51a81d9..8600474 100644 (file)
@@ -9,19 +9,20 @@ $prefGroups['view'] = array(
     'column' => _("Display Options"),
     'label' => _("User Interface"),
     'desc' => _("Select confirmation options, how to display the different views and choose default view."),
-    'members' => array('dynamic_view', 'confirm_delete', 'defaultview',
-                       'max_events', 'time_between_days', 'week_start_monday',
-                       'day_hour_start', 'day_hour_end', 'day_hour_force',
-                       'slots_per_hour', 'show_icons', 'show_time',
-                       'show_location', 'show_fb_legend',
-                       'show_shared_side_by_side'),
+    'members' => array(
+        'dynamic_view', 'confirm_delete', 'defaultview', 'max_events',
+        'time_between_days', 'week_start_monday', 'day_hour_start',
+        'day_hour_end', 'day_hour_force', 'slots_per_hour', 'show_icons',
+        'show_time', 'show_location', 'show_fb_legend',
+        'show_shared_side_by_side'
+    ),
 );
 
 $prefGroups['share'] = array(
     'column' => _("Calendars"),
     'label' => _("Default Calendar"),
     'desc' => _("Choose your default calendar."),
-    'members' => array('shareselect'),
+    'members' => array('default_share'),
 );
 
 $prefGroups['event_options'] = array(
@@ -35,40 +36,38 @@ $prefGroups['logintasks'] = array(
     'column' => _("Events"),
     'label' => _("Login Tasks"),
     'desc' => sprintf(_("Customize tasks to run upon logon to %s."), $GLOBALS['registry']->get('name')),
-    'members' => array('purge_events', 'purge_events_interval', 'purge_events_keep')
+    'members' => array(
+        'purge_events', 'purge_events_interval', 'purge_events_keep'
+    )
 );
 
 $prefGroups['notification'] = array(
     'column' => _("Events"),
     'label' => _("Notifications"),
     'desc' => _("Choose how you want to be notified about event changes, event alarms and upcoming events."),
-    'members' => array('event_notification', 'event_notification_exclude_self', 'daily_agenda', 'event_reminder'),
+    'members' => array(
+        'event_notification', 'event_notification_exclude_self',
+        'daily_agenda', 'event_reminder', 'event_alarms'
+    )
 );
-if (!empty($GLOBALS['conf']['alarms']['driver'])) {
-    $prefGroups['notification']['members'][] = 'event_alarms';
-}
 
 $prefGroups['freebusy'] = array(
     'column' => _("Calendars"),
     'label' => _("Free/Busy Information"),
     'desc' => _("Set your Free/Busy calendars and your own and other users' Free/Busy options."),
-    'members' => array('fb_cals_select', 'freebusy_days'),
+    'members' => array('fb_url', 'fb_cals', 'freebusy_days'),
 );
 
-if ($GLOBALS['registry']->hasMethod('contacts/sources')) {
-    $prefGroups['addressbooks'] = array(
-        'column' => _("Other Options"),
-        'label' => _("Address Books"),
-        'desc' => _("Select address book sources for adding and searching for addresses."),
-        'members' => array('display_contact', 'sourceselect'),
-    );
-}
+$prefGroups['addressbooks'] = array(
+    'column' => _("Other Options"),
+    'label' => _("Address Books"),
+    'desc' => _("Select address book sources for adding and searching for addresses."),
+    'members' => array('display_contact', 'sourceselect'),
+);
 
 // show dynamic view?
 $_prefs['dynamic_view'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show the dynamic view by default, if the browser supports it?")
 );
@@ -76,8 +75,6 @@ $_prefs['dynamic_view'] = array(
 // confirm deletion of events which don't recur?
 $_prefs['confirm_delete'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Confirm deletion of events?")
 );
@@ -85,20 +82,18 @@ $_prefs['confirm_delete'] = array(
 // default view
 $_prefs['defaultview'] = array(
     'value' => 'month',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('day' => _("Day"),
-                    'week' => _("Week"),
-                    'workweek' => _("Work Week"),
-                    'month' => _("Month")),
+    'enum' => array(
+        'day' => _("Day"),
+        'week' => _("Week"),
+        'workweek' => _("Work Week"),
+        'month' => _("Month")
+    ),
     'desc' => _("Select the view to display on startup:")
 );
 
 $_prefs['max_events'] = array(
     'value' => 3,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("How many events should be displayed per day in the month view? Set to 0 to always show all events."),
 );
@@ -106,8 +101,6 @@ $_prefs['max_events'] = array(
 // Display the timeslots between each day column, in week view.
 $_prefs['time_between_days'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show time of day between each day in week views?")
 );
@@ -115,37 +108,33 @@ $_prefs['time_between_days'] = array(
 // what day does the week start with
 $_prefs['week_start_monday'] = array(
     'value' => '0',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'desc' => _("Select the first weekday:"),
-    'enum' => array('0' => _("Sunday"),
-                    '1' => _("Monday"))
+    'enum' => array(
+        '0' => _("Sunday"),
+        '1' => _("Monday")
+    )
 );
 
 // start of the time range in day/week views:
+// Time array is dynamically built when prefs screen is displayed
 $_prefs['day_hour_start'] = array(
     'value' => 16,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'select',
+    'type' => 'enum',
     'desc' => _("What time should day and week views start, when there are no earlier events?")
 );
 
 // end of the time range in day/week views:
+// Time array is dynamically built when prefs screen is displayed
 $_prefs['day_hour_end'] = array(
     'value' => 48,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'select',
+    'type' => 'enum',
     'desc' => _("What time should day and week views end, when there are no later events?")
 );
 
 // enforce hour slots?
 $_prefs['day_hour_force'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Restrict day and week views to these time slots, even if there <strong>are</strong> earlier or later events?"),
 );
@@ -153,22 +142,19 @@ $_prefs['day_hour_force'] = array(
 // number of slots in each hour:
 $_prefs['slots_per_hour'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'desc' => _("How long should the time slots on the day and week views be?"),
-    'enum' => array(4 => _("15 minutes"),
-                    3 => _("20 minutes"),
-                    2 => _("30 minutes"),
-                    1 => _("1 hour"),
+    'enum' => array(
+        4 => _("15 minutes"),
+        3 => _("20 minutes"),
+        2 => _("30 minutes"),
+        1 => _("1 hour")
     ),
 );
 
 // show delete/alarm icons in the calendar view?
 $_prefs['show_icons'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show delete, alarm, and recurrence icons in calendar views?"),
 );
@@ -176,11 +162,10 @@ $_prefs['show_icons'] = array(
 // show event start/end times in the calendar and/or print views?
 $_prefs['show_time'] = array(
     'value' => 'a:1:{i:0;s:5:"print";}',
-    'locked' => false,
-    'shared' => false,
     'type' => 'multienum',
-    'enum' => array('screen' => _("Month, Week, and Day Views"),
-                    'print' => _("Print Views"),
+    'enum' => array(
+        'screen' => _("Month, Week, and Day Views"),
+        'print' => _("Print Views")
      ),
     'desc' => _("Choose the views to show event start and end times in:"),
 );
@@ -188,11 +173,10 @@ $_prefs['show_time'] = array(
 // show event location in the calendar and/or print views?
 $_prefs['show_location'] = array(
     'value' => 'a:1:{i:0;s:5:"print";}',
-    'locked' => false,
-    'shared' => false,
     'type' => 'multienum',
-    'enum' => array('screen' => _("Month, Week, and Day Views"),
-                    'print' => _("Print Views"),
+    'enum' => array(
+        'screen' => _("Month, Week, and Day Views"),
+        'print' => _("Print Views")
      ),
     'desc' => _("Choose the views to show event locations in:"),
 );
@@ -200,18 +184,13 @@ $_prefs['show_location'] = array(
 // show the calendar options panel?
 // a value of 0 = no, 1 = yes
 $_prefs['show_panel'] = array(
-    'value' => 1,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => 1
 );
 
 // show Free/Busy legend?
 // a value of 0 = no, 1 = yes
 $_prefs['show_fb_legend'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show Free/Busy legend?"),
 );
@@ -219,103 +198,78 @@ $_prefs['show_fb_legend'] = array(
 // collapsed or side by side view
 $_prefs['show_shared_side_by_side'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show shared calendars side-by-side?"),
 );
 
-// default calendar selection widget
-$_prefs['shareselect'] = array('type' => 'special');
-
 // default calendar
 // Set locked to true if you don't want users to have multiple calendars.
 $_prefs['default_share'] = array(
     'value' => Horde_Auth::getAuth() ? Horde_Auth::getAuth() : 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'type' => 'enum',
+    'desc' => _("Your default calendar:")
 );
 
 // Which drivers are we supposed to use to examine holidays?
 $_prefs['holiday_drivers'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => 'a:0:{}'
 );
 
 // store the calendars to diplay
 $_prefs['display_cals'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => 'a:0:{}'
 );
 
 // default alarm
 $_prefs['default_alarm'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ''
 );
+
 $_prefs['default_alarm_management'] = array('type' => 'special');
 
 // remote calendars
 $_prefs['remote_cals'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => 'a:0:{}'
 );
 
 // store the remote calendars to display
 $_prefs['display_remote_cals'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => 'a:0:{}'
 );
 
 // store the external calendars to display
 $_prefs['display_external_cals'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => 'a:0:{}'
 );
 
 // new event notifications
 $_prefs['event_notification'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('' => _("No"),
-                    'owner' => _("On my calendars only"),
-                    'show' => _("On all shown calendars"),
-                    'read' => _("On all calendars I have read access to")),
+    'enum' => array(
+        '' => _("No"),
+        'owner' => _("On my calendars only"),
+        'show' => _("On all shown calendars"),
+        'read' => _("On all calendars I have read access to")
+    ),
     'desc' => _("Choose if you want to be notified of new, edited, and deleted events by email:")
 );
 
 // daily agenda
 $_prefs['daily_agenda'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('' => _("No"),
-                    'owner' => _("On my calendars only"),
-                    'show' => _("On all shown calendars"),
-                    'read' => _("On all calendars I have read access to")),
+    'enum' => array(
+        '' => _("No"),
+        'owner' => _("On my calendars only"),
+        'show' => _("On all shown calendars"),
+        'read' => _("On all calendars I have read access to")
+    ),
     'desc' => _("Choose if you want to receive daily agenda email reminders:")
 );
 
 $_prefs['event_notification_exclude_self'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Don't send me a notification if I've added, changed or deleted the event?")
 );
@@ -323,21 +277,19 @@ $_prefs['event_notification_exclude_self'] = array(
 // reminder notifications
 $_prefs['event_reminder'] = array(
     'value' => 'owner',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('' => _("No"),
-                    'owner' => _("On my calendars only"),
-                    'show' => _("On all shown calendars"),
-                    'read' => _("On all calendars I have read access to")),
+    'enum' => array(
+        '' => _("No"),
+        'owner' => _("On my calendars only"),
+        'show' => _("On all shown calendars"),
+        'read' => _("On all calendars I have read access to")
+    ),
     'desc' => _("Choose if you want to receive reminders for events with alarms:")
 );
 
 // alarm methods
 $_prefs['event_alarms'] = array(
     'value' => 'a:1:{s:6:"notify";a:0:{}}',
-    'locked' => false,
-    'shared' => false,
     'type' => 'alarm',
     'desc' => _("Choose how you want to receive reminders for events with alarms:")
 );
@@ -345,8 +297,6 @@ $_prefs['event_alarms'] = array(
 // number of days to generate Free/Busy information for:
 $_prefs['freebusy_days'] = array(
     'value' => 30,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("How many days of Free/Busy information should be generated?")
 );
@@ -356,7 +306,6 @@ $_prefs['freebusy_days'] = array(
 // slow to display, you may want to disable and lock this option.
 $_prefs['display_contact'] = array(
     'value' => 1,
-    'locked' => false,
     'shared' => true,
     'type' => 'checkbox',
     'desc' => _("List all contacts when loading the contacts screen? (if disabled, you will only see contacts that you search for explicitly)"),
@@ -370,10 +319,7 @@ $_prefs['sourceselect'] = array('type' => 'special');
 // 'value' => "source_one\tsource_two"
 // refer to turba/config/sources.php for possible source values
 $_prefs['search_sources'] = array(
-    'value' => "",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ""
 );
 
 // field(s) to use when expanding addresses
@@ -384,39 +330,31 @@ $_prefs['search_sources'] = array(
 // 'field_three' in source_two.
 // refer to turba/config/sources.php for possible source and field values
 $_prefs['search_fields'] = array(
-    'value' => "",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ""
+);
+
+$_prefs['fb_url'] = array(
+    'value' => '<strong>' . _("My Free/Busy URL") . '</strong><div class="fburl"><div>' . _("Copy this URL for use wherever you need your Free/Busy URL:") . '</div><div class="fixed">' . Horde::applicationUrl('fb.php', true, -1)->add('u', Horde_Auth::getAuth()) . '</div></div>',
+    'type' => 'rawhtml'
 );
 
 // Calendars to include in generating Free/Busy URLs.
 $_prefs['fb_cals'] = array(
     'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
-    'desc' => _("Choose the calendars to include when generating Free/Busy URLs:")
+    'type' => 'multienum',
+    'desc' => _("Choose the calendars to include in the above Free/Busy URL:"))
 );
 
-// Free/Busy calendars selector.
-$_prefs['fb_cals_select'] = array('type' => 'special');
-
-
 // Login Tasks preferences
 
 $_prefs['purge_events'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Purge old events from your calendar?"),
 );
 
 $_prefs['purge_events_interval'] = array(
     'value' => Horde_LoginTasks::MONTHLY,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => Horde_LoginTasks::getLabels(),
     'desc' => _("Purge old events how often:"),
@@ -424,8 +362,6 @@ $_prefs['purge_events_interval'] = array(
 
 $_prefs['purge_events_keep'] = array(
     'value' => 365,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Purge old events older than this amount of days."),
 );
index 32e83aa..1781e88 100644 (file)
@@ -27,7 +27,7 @@ if ($help_link) {
     $help_link = Horde::widget($help_link, _("Help"), 'helplink', 'help', Horde::popupJs($help_link, array('urlencode' => true)) . 'return false;');
 }
 $today = new Horde_Date($_SERVER['REQUEST_TIME']);
-$_SESSION['horde_prefs']['nomenu'] = true;
+Horde_Core_Prefs_Ui::hideMenu(true);
 
 $alarm_methods = $alarm_params = '';
 foreach (Horde_Alarm::notificationMethods() as $method => $params) {
index 5d35b6d..b48eb62 100644 (file)
@@ -109,63 +109,136 @@ class Kronolith_Application extends Horde_Registry_Application
     }
 
     /**
-     * Code to run when viewing prefs for this application.
+     * Code to run on init when viewing prefs for this application.
      *
-     * @param string $group  The prefGroup name.
-     *
-     * @return array  A list of variables to export to the prefs display page.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsInit($group)
+    public function prefsInit($ui)
     {
-        $out = array();
+        global $conf, $prefs, $registry;
+
+        switch ($ui->group) {
+        case 'addressbooks':
+            if (!$prefs->isLocked('sourceselect')) {
+                Horde_Core_Prefs_Ui_Widgets::addressbooksInit($ui);
+            }
+            break;
+
+        case 'freebusy':
+            if (!$prefs->isLocked('fb_cals')) {
+                $fb_cals = Kronolith::ListCalendars();
+                $fb_list = array();
+                foreach (Kronolith::ListCalendars() as $fb_cal => $cal) {
+                    $fb_list[htmlspecialchars($fb_cal)] = htmlspecialchars($cal->get('name'));
+                }
+                $ui->override['fb_cals'] = $fb_list;
+            }
+            break;
 
-        if (!$GLOBALS['prefs']->isLocked('day_hour_start') ||
-            !$GLOBALS['prefs']->isLocked('day_hour_end')) {
-            $out['day_hour_start_options'] = array();
-            for ($i = 0; $i <= 48; ++$i) {
-                $out['day_hour_start_options'][$i] = date(($GLOBALS['prefs']->getValue('twentyFour')) ? 'G:i' : 'g:ia', mktime(0, $i * 30, 0));
+        case 'notification':
+            if (empty($conf['alarms']['driver'])) {
+                $ui->suppress[]= 'event_alarms';
             }
-            $out['day_hour_end_options'] = $out['day_hour_start_options'];
+            break;
+
+       case 'share':
+            if (!$prefs->isLocked('default_share')) {
+                $all_tasklists = Kronolith::listCalendars();
+                $sharelist = array();
+
+                foreach ($all_shares as $id => $share) {
+                    if (!empty($conf['share']['hidden']) &&
+                        ($share->get('owner') != Horde_Auth::getAuth()) &&
+                        !in_array($share->getName(), $GLOBALS['display_calendars'])) {
+                        continue;
+                    }
+                    $sharelist[$id] = $share;
+                }
+
+                $vals = array();
+                foreach ($sharelist as $id => $share) {
+                    $vals[htmlspecialchars($id)] = htmlspecialchars($share->get('name'));
+                }
+                $ui->override['default_share'] = $vals;
+            }
+            break;
+
+        case 'view':
+            if (!$prefs->isLocked('day_hour_start') ||
+                !$prefs->isLocked('day_hour_end')) {
+                $out = array();
+                $tf = $GLOBALS['prefs']->getValue('twentyFour') ? 'G:i' : 'g:ia';
+                for ($i = 0; $i <= 48; ++$i) {
+                    $out[$i] = date($tf, mktime(0, $i * 30, 0));
+                }
+                $ui->override['day_hour_end'] = $out;
+                $ui->override['day_hour_start'] = $out;
+            }
+            break;
+        }
+
+        /* Suppress prefGroups display. */
+        if (!$registry->hasMethod('contacts/sources')) {
+            $ui->suppressGroups[] = 'addressbooks';
         }
 
-        return $out;
+        if ($prefs->isLocked('default_alarm')) {
+            $ui->suppressGroups[] = 'event_options';
+        }
     }
 
-    /**
-     * Special preferences handling on update.
+   /**
+     * Generate code used to display a special preference.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
-     * @return boolean  True if preference was updated.
+     * @return string  The HTML code to display on the options page.
      */
-    public function prefsSpecial($item, $updated)
+    public function prefsSpecial($ui, $item)
     {
         switch ($item) {
-        case 'remote_cal_management':
-            return $this->_prefsRemoteCalManagement($updated);
-
-        case 'shareselect':
-            return $this->_prefsShareSelect($updated);
+        case 'default_alarm_management':
+            return $this->_defaultAlarmManagement($ui);
 
         case 'sourceselect':
-            return $this->_prefsSourceSelect($updated);
+            return Horde_Core_Prefs_Ui_Widgets::addressbooks($ui);
+        }
 
-        case 'fb_cals_select':
-            $this->_prefsFbCalsSelect($updated);
-            return true;
+        return '';
+    }
 
+    /**
+     * Special preferences handling on update.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return boolean  True if preference was updated.
+     */
+    public function prefsSpecialUpdate($ui, $item)
+    {
+        switch ($item) {
         case 'default_alarm_management':
-            $GLOBALS['prefs']->setValue('default_alarm', (int)Horde_Util::getFormData('alarm_value') * (int)Horde_Util::getFormData('alarm_unit'));
+            $GLOBALS['prefs']->setValue('default_alarm', (int)$ui->vars->alarm_value * (int)$ui->vars->alarm_unit);
             return true;
+
+        case 'remote_cal_management':
+            return $this->_prefsRemoteCalManagement($ui);
+
+        case 'sourceselect':
+            return Horde_Core_Prefs_Ui_Widgets::addressbooksUpdate($ui);
         }
+
+        return false;
     }
 
     /**
-     * Do anything that we need to do as a result of certain preferences
-     * changing.
+     * Called when preferences are changed.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsCallback()
+    public function prefsCallback($ui)
     {
         if ($GLOBALS['prefs']->isDirty('event_alarms')) {
             try {
@@ -178,30 +251,69 @@ class Kronolith_Application extends Horde_Registry_Application
                         $horde_alarm->set($alarm);
                     }
                 }
-            } catch (Exception $e) {
-            }
+            } catch (Exception $e) {}
         }
     }
 
     /**
      * Generate the menu to use on the prefs page.
      *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
      * @return Horde_Menu  A Horde_Menu object.
      */
-    public function prefsMenu()
+    public function prefsMenu($ui)
     {
         return Kronolith::getMenu();
     }
 
     /**
-     * TODO
+     * Create code for default alarm management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
      */
-    protected function _prefsRemoteCalManagement($updated)
+    protected function _defaultAlarmManagement($ui)
     {
-        $calName = Horde_Util::getFormData('remote_name');
-        $calUrl  = trim(Horde_Util::getFormData('remote_url'));
-        $calUser = trim(Horde_Util::getFormData('remote_user'));
-        $calPasswd = trim(Horde_Util::getFormData('remote_password'));
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+
+        if ($alarm_value = $prefs->getValue('default_alarm')) {
+            if ($alarm_value % 10080 == 0) {
+                $alarm_value /= 10080;
+                $t->set('week', true);
+            } elseif ($alarm_value % 1440 == 0) {
+                $alarm_value /= 1440;
+                $t->set('day', true);
+            } elseif ($alarm_value % 60 == 0) {
+                $alarm_value /= 60;
+                $t->set('hour', true);
+            } else {
+                $t->set('minute', true);
+            }
+        } else {
+            $t->set('minute', true);
+        }
+
+        $t->set('alarm_value', intval($alarm_value));
+
+        return $t->fetch(KRONOLITH_TEMPLATES . '/prefs/defaultalarm.html');
+    }
+
+    /**
+     * Create code for remote calendar management.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
+     * @return string  HTML UI code.
+     */
+    protected function _prefsRemoteCalManagement($ui)
+    {
+        $calName = $ui->vars->remote_name;
+        $calUrl  = trim($ui->vars->remote_url);
+        $calUser = trim($ui->vars->remote_user);
+        $calPasswd = trim($ui->vars->remote_password);
 
         $key = Horde_Auth::getCredential('password');
         if ($key) {
@@ -209,7 +321,9 @@ class Kronolith_Application extends Horde_Registry_Application
             $calPasswd = base64_encode(Secret::write($key, $calPasswd));
         }
 
-        $calActionID = Horde_Util::getFormData('remote_action', 'add');
+        $calActionID = isset($ui->vars->remote_action)
+            ? $ui->vars->remote_action
+            : 'add';
 
         if ($calActionID == 'add') {
             if (!empty($calName) && !empty($calUrl)) {
@@ -219,7 +333,6 @@ class Kronolith_Application extends Horde_Registry_Application
                     'user' => $calUser,
                     'password' => $calPasswd);
                 $GLOBALS['prefs']->setValue('remote_cals', serialize($cals));
-                return $updated;
             }
         } elseif ($calActionID == 'delete') {
             $cals = unserialize($GLOBALS['prefs']->getValue('remote_cals'));
@@ -230,7 +343,6 @@ class Kronolith_Application extends Horde_Registry_Application
                 }
             }
             $GLOBALS['prefs']->setValue('remote_cals', serialize($cals));
-            return $updated;
         } elseif ($calActionID == 'edit') {
             $cals = unserialize($GLOBALS['prefs']->getValue('remote_cals'));
             foreach ($cals as $key => $cal) {
@@ -243,66 +355,7 @@ class Kronolith_Application extends Horde_Registry_Application
                 }
             }
             $GLOBALS['prefs']->setValue('remote_cals', serialize($cals));
-            return $updated;
         }
-
-        return false;
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsShareSelect($updated)
-    {
-        $default_share = Horde_Util::getFormData('default_share');
-        if (!is_null($default_share)) {
-            $sharelist = Kronolith::listCalendars();
-            if (isset($sharelist[$default_share]) &&
-                ($sharelist[$default_share]->get('owner') == Horde_Auth::getAuth() ||
-                 in_array($default_share, $GLOBALS['display_calendars']))) {
-                $GLOBALS['prefs']->setValue('default_share', $default_share);
-                return true;
-            }
-        }
-
-        return $updated;
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsSourceSelect($updated)
-    {
-        $search_sources = Horde_Util::getFormData('search_sources');
-        if (!is_null($search_sources)) {
-            $GLOBALS['prefs']->setValue('search_sources', $search_sources);
-            $updated = true;
-        }
-
-        $search_fields_string = Horde_Util::getFormData('search_fields_string');
-        if (!is_null($search_fields_string)) {
-            $GLOBALS['prefs']->setValue('search_fields', $search_fields_string);
-            $updated = true;
-        }
-
-        return $updated;
-    }
-
-    /**
-     * TODO
-     */
-    protected function _prefsFbCalsSelect()
-    {
-        $fb_calsSelected = Horde_Util::getFormData('fb_cals');
-        $fb_calsFiltered = array();
-
-        if (isset($fb_calsSelected) && is_array($fb_calsSelected)) {
-            foreach ($fb_calsSelected as $fb_cal) {
-                $fb_calsFiltered[] = $fb_cal;
-            }
-        }
-
-        $GLOBALS['prefs']->setValue('fb_cals', serialize($fb_calsFiltered));
     }
 
     /**
diff --git a/kronolith/templates/prefs/default_alarm_management.inc b/kronolith/templates/prefs/default_alarm_management.inc
deleted file mode 100644 (file)
index a116854..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php if (!$prefs->isLocked('default_alarm')):
-
-$alarm_value = $prefs->getValue('default_alarm');
-if (!$alarm_value) {
-    $alarm_unit = 'min';
-} else {
-    if ($alarm_value % 10080 == 0) {
-        $alarm_value /= 10080;
-        $alarm_unit = 'week';
-    } elseif ($alarm_value % 1440 == 0) {
-        $alarm_value /= 1440;
-        $alarm_unit = 'day';
-    } elseif ($alarm_value % 60 == 0) {
-        $alarm_value /= 60;
-        $alarm_unit = 'hour';
-    } else {
-        $alarm_unit = 'min';
-    }
-}
-?>
-<?php echo _("Default Alarm Setting:") ?><br />
-<label for="alarm_value" class="hidden"><?php echo _("Alarm Value") ?></label>
-<input type="text" size="2" id="alarm_value" name="alarm_value" value="<?php echo (int)$alarm_value ?>" />&nbsp;
-<label for="alarm_unit" class="hidden"><?php echo _("Alarm Unit") ?></label>
-<select id="alarm_unit" name="alarm_unit">
- <option value="1"<?php echo ($alarm_unit == 'min') ? ' selected="selected"' : '' ?>><?php echo _("Minute(s)") ?></option>
- <option value="60"<?php echo ($alarm_unit == 'hour') ? ' selected="selected"' : '' ?>><?php echo _("Hour(s)") ?></option>
- <option value="1440"<?php echo ($alarm_unit == 'day') ? ' selected="selected"' : '' ?>><?php echo _("Day(s)") ?></option>
- <option value="10080"<?php echo ($alarm_unit == 'week') ? ' selected="selected"' : '' ?>><?php echo _("Week(s)") ?></option>
-</select>
-<?php echo _("before the event starts. A value of \"0\" means no default alarms.") ?>
-<?php endif; ?>
diff --git a/kronolith/templates/prefs/defaultalarm.html b/kronolith/templates/prefs/defaultalarm.html
new file mode 100644 (file)
index 0000000..af9c32f
--- /dev/null
@@ -0,0 +1,16 @@
+<div>
+ <gettext>Default Alarm Setting:</gettext>
+</div>
+
+<div>
+ <label for="alarm_value" class="hidden"><gettext>Alarm Value</gettext></label>
+ <input type="text" size="2" id="alarm_value" name="alarm_value" value="<tag:alarm_value />" />
+ <label for="alarm_unit" class="hidden"><gettext>Alarm Unit</gettext></label>
+ <select id="alarm_unit" name="alarm_unit">
+  <option value="1"<if:minute> selected="selected"</if:minute>><gettext>Minute(s)</gettext></option>
+  <option value="60"<if:hour> selected="selected"</if:hour>><gettext>Hour(s)</gettext></option>
+  <option value="1440"<if:day> selected="selected"</if:day>><gettext>Day(s)</gettext></option>
+  <option value="10080"<if:week> selected="selected"</if:week>><gettext>Week(s)</gettext></option>
+ </select>
+ <gettext>before the event starts. A value of "0" means no default alarms.</gettext>
+</div>
diff --git a/kronolith/templates/prefs/fb_cals_select.inc b/kronolith/templates/prefs/fb_cals_select.inc
deleted file mode 100644 (file)
index 6c2a4a1..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<h1 class="header">
- <?php echo _("My Free/Busy URL") ?>
-</h1>
-<div class="headerbox">
- <div class="control">
-  <?php echo _("Copy this URL for use wherever you need your Free/Busy URL:") ?>
- </div>
- <p class="text">
-  <?php echo Horde::applicationUrl('fb.php', true, -1)->add('u', Horde_Auth::getAuth()) ?>
- </p>
-</div>
-
-<br class="spacer" />
-<?php
-if (!$prefs->isLocked('fb_cals')) {
-    $fb_cals = Kronolith::ListCalendars();
-    $fb_calsSaved = unserialize($prefs->getValue('fb_cals'));
-    $fb_calSelect = '';
-    foreach ($fb_cals as $fb_cal => $cal) {
-        if (!is_bool(array_search($fb_cal, $fb_calsSaved))) {
-            $fb_calSelect .= '<option value="' . htmlspecialchars($fb_cal) . '" selected="selected">' . htmlspecialchars($cal->get('name')) . '</option>';
-        } else {
-            $fb_calSelect .= '<option value="' . htmlspecialchars($fb_cal) . '">' . htmlspecialchars($cal->get('name')) . '</option>';
-        }
-    }
-
-    if ($fb_calSelect) {
-        echo Horde::label('fb_cals', _("Choose the calendars to include in the above Free/Busy URL:")) . '<br />' .
-            '<select multiple="multiple" id="fb_cals" name="fb_cals[]">' . $fb_calSelect . '</select><br /><br class="spacer" />';
-    }
-}
diff --git a/kronolith/templates/prefs/shareselect.inc b/kronolith/templates/prefs/shareselect.inc
deleted file mode 100644 (file)
index 6e23c56..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-if (!$prefs->isLocked('default_share')):
-    $all_shares = Kronolith::listCalendars();
-    $sharelist = array();
-    foreach ($all_shares as $id => $share) {
-        if ($share->get('owner') != Horde_Auth::getAuth() &&
-            !empty($GLOBALS['conf']['share']['hidden']) &&
-            !in_array($share->getName(), $GLOBALS['display_calendars'])) {
-            continue;
-        }
-        $sharelist[$id] = $share;
-    }
-    if (($default_share = $prefs->getValue('default_share')) == null ||
-        !isset($sharelist[$default_share])) {
-        $default_share = Horde_Auth::getAuth();
-    }
-?>
-
-    <?php echo Horde::label('default_share', _("Your default calendar")) ?><br />
-    <select id="default_share" name="default_share">
-     <?php foreach ($sharelist as $id => $share): ?>
-     <option value="<?php echo htmlspecialchars($id) ?>"<?php if ($id == $default_share) echo ' selected="selected"' ?>><?php echo htmlspecialchars($share->get('name')) ?></option>
-     <?php endforeach; ?>
-    </select>
-<?php endif; ?>
diff --git a/kronolith/templates/prefs/sourceselect.inc b/kronolith/templates/prefs/sourceselect.inc
deleted file mode 100644 (file)
index 774d5eb..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-<?php
-if ($registry->hasMethod('contacts/sources')) {
-    $selected = explode("\t", $prefs->getValue('search_sources'));
-    try {
-        $readable = $registry->call('contacts/sources');
-    } catch (Horde_Exception $e) {
-        $readable = null;
-    }
-    try {
-        $writeable = $registry->call('contacts/sources', array(true));
-    } catch (Horde_Exception $e) {
-        $writeable = null;
-    }
-
-    $nbReadSources = count(array_keys($readable));
-    $nbWriteSources = count(array_keys($writeable));
-
-    if (count($selected) == 1 && empty($selected[0])) {
-        $selected = array();
-    }
-
-    if ($nbReadSources == 1) {
-        // Only one source, no need to display the selection widget
-        $selected = array_keys($readable);
-        $readSelect = '';
-    }
-
-    $prefSelect = '';
-    foreach ($selected as $source) {
-        if (!empty($readable[$source])) {
-            $prefSelect .= '<option value="' . $source . '">' . $readable[$source] . "</option>\n";
-        }
-    }
-
-    $readSelect = '';
-    if (is_array($readable)) {
-        foreach (array_diff(array_keys($readable), $selected) as $source) {
-            $readSelect .= '<option value="' . $source . '">' . $readable[$source] . "</option>\n";
-        }
-    }
-
-    if (is_array($writeable)) {
-        $writeSelect = '<option value="">' . _("None") . '</option>' . "\n";
-        $writeSource = '';
-        foreach ($writeable as $source => $name) {
-            $sel = $prefs->getValue('add_source') == $source ? ' selected="selected"' : '';
-            $writeSelect .= '<option value="' . $source . '"' . "$sel>" . $name . "</option>\n";
-            $writeSource = $source;
-        }
-    }
-
-    $selected_fields = array();
-    $search_field_pref = $prefs->getValue('search_fields');
-    if (!empty($search_field_pref)) {
-        $selected_fields = explode("\n", $prefs->getValue('search_fields'));
-        foreach ($selected_fields as $field) {
-            $field = trim($field);
-            if (!empty($field)) {
-                $tmp = explode("\t", $field);
-                if (count($tmp) > 1) {
-                    $source = array_splice($tmp, 0, 1);
-                    $selected_fields[$source[0]] = $tmp;
-                }
-            }
-        }
-    }
-
-    $search_fields = array();
-    if (is_array($readable)) {
-        foreach (array_keys($readable) as $source) {
-            try {
-                $search_fields[$source] = $registry->call('contacts/fields', array($source));
-            } catch (Horde_Exception $e) {}
-        }
-    }
-
-    $js = "var searchFields = [];\n";
-    $source_count = 0;
-    foreach ($search_fields as $source => $fields) {
-        $js .= "searchFields[$source_count] = [];\n";
-        $js .= "searchFields[$source_count][0] = '$source';\n";
-
-        $field_count = 1;
-        foreach ($fields as $field) {
-            if ($field['search']) {
-                $marked = isset($selected_fields[$source]) && in_array($field['name'], $selected_fields[$source]) ? 'true' : 'false';
-                $js .= "searchFields[$source_count][$field_count] = ['" . $field['name'] . "', '" . $field['label'] . "', $marked];\n";
-                $field_count++;
-            }
-        }
-
-        $source_count++;
-    }
-}
-?>
-
-<?php if (!$prefs->isLocked('search_sources') && (!empty($readSelect) || !empty($prefSelect))): ?>
-<script type="text/javascript">
-function deselectHeaders()
-{
-    document.prefs.unselected_search_sources[0].selected = false;
-    document.prefs.selected_search_sources[0].selected = false;
-}
-
-function resetHidden()
-{
-    var tmp = '';
-    for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-        tmp += document.prefs.selected_search_sources[i].value;
-        if (i < document.prefs.selected_search_sources.length - 1)
-            tmp += "\t";
-    }
-
-    document.prefs.search_sources.value = tmp;
-}
-
-function addSource()
-{
-    for (i = 1; i < document.prefs.unselected_search_sources.length; i++) {
-        if (document.prefs.unselected_search_sources[i].selected) {
-            document.prefs.selected_search_sources[document.prefs.selected_search_sources.length] = new Option(document.prefs.unselected_search_sources[i].text, document.prefs.unselected_search_sources[i].value);
-            document.prefs.unselected_search_sources[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function removeSource()
-{
-    for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-        if (document.prefs.selected_search_sources[i].selected) {
-            document.prefs.unselected_search_sources[document.prefs.unselected_search_sources.length] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-            document.prefs.selected_search_sources[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function moveSourceUp()
-{
-    var sel = document.prefs.selected_search_sources.selectedIndex;
-
-    if (sel == -1 || document.prefs.selected_search_sources.length <= 2) return;
-
-    // deselect everything but the first selected item
-    document.prefs.selected_search_sources.selectedIndex = sel;
-
-    if (sel == 1) {
-        tmp = document.prefs.selected_search_sources[sel];
-        document.prefs.selected_search_sources[sel] = null;
-        document.prefs.selected_search_sources[document.prefs.selected_search_sources.length] = tmp;
-        document.prefs.selected_search_sources.selectedIndex = document.prefs.selected_search_sources.length - 1;
-    } else {
-        tmp = [];
-        for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-            tmp[i - 1] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-        }
-
-        for (i = 0; i < tmp.length; i++) {
-            if (i + 1 == sel - 1) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i + 1];
-            } else if (i + 1 == sel) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i - 1];
-            } else {
-                document.prefs.selected_search_sources[i + 1] = tmp[i];
-            }
-        }
-
-        document.prefs.selected_search_sources.selectedIndex = sel - 1;
-    }
-
-    resetHidden();
-}
-
-function moveSourceDown()
-{
-    var sel = document.prefs.selected_search_sources.selectedIndex;
-
-    if (sel == -1 || document.prefs.selected_search_sources.length <= 2) return;
-
-    // deselect everything but the first selected item
-    document.prefs.selected_search_sources.selectedIndex = sel;
-
-    if (sel == document.prefs.selected_search_sources.length - 1) {
-        tmp = [];
-        for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-            tmp[i - 1] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-        }
-
-        document.prefs.selected_search_sources[1] = tmp[tmp.length - 1];
-        for (i = 0; i < tmp.length - 1; i++) {
-            document.prefs.selected_search_sources[i + 2] = tmp[i];
-        }
-
-        document.prefs.selected_search_sources.selectedIndex = 1;
-    } else {
-        tmp = [];
-        for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-            tmp[i - 1] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-        }
-
-        for (i = 0; i < tmp.length; i++) {
-            if (i + 1 == sel) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i + 1];
-            } else if (i + 1 == sel + 1) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i - 1];
-            } else {
-                document.prefs.selected_search_sources[i + 1] = tmp[i];
-            }
-        }
-
-        document.prefs.selected_search_sources.selectedIndex = sel + 1;
-    }
-
-    resetHidden();
-}
-
-<?php echo $js ?>
-
-var selectedIndex = false;
-var selectedValue = false;
-var nbSources = <?php echo $nbReadSources ?>;
-<?php if ($nbReadSources == 1): ?>
-selectedIndex = 1;
-selectedValue = "<?php echo $selected[0] ?>";
-<?php endif; ?>
-
-function updateSearchFields()
-{
-    var f = document.prefs;
-    <?php if ($nbReadSources > 1): ?>
-    selectedIndex = f.selected_search_sources.selectedIndex;
-    <?php endif; ?>
-    var fieldString = '';
-
-    while (f.search_fields.length > 0) {
-        f.search_fields.options[f.search_fields.length-1] = null;
-    }
-
-    if (selectedIndex < 1) {
-        return;
-    }
-
-    <?php if ($nbReadSources > 1): ?>
-    selectedValue = f.selected_search_sources.options[selectedIndex].value;
-    <?php endif; ?>
-
-    for (var i = 0; i < searchFields.length; i++) {
-        if (i > 0) {
-            fieldString += "\n";
-        }
-        fieldString += searchFields[i][0];
-        for (var j = 1; j < searchFields[i].length; j++) {
-            if (searchFields[i][j][2]) {
-                fieldString += "\t" + searchFields[i][j][0];
-            }
-
-            if (searchFields[i][0] == selectedValue) {
-                f.search_fields.options[f.search_fields.length] = new Option(searchFields[i][j][1], searchFields[i][j][0]);
-                if (searchFields[i][j][2]) {
-                    f.search_fields.options[f.search_fields.length - 1].selected = true;
-                }
-            }
-        }
-    }
-
-    f.search_fields_string.value = fieldString;
-}
-
-function changeSearchFields()
-{
-    var f = document.prefs;
-    <?php if ($nbReadSources > 1): ?>
-    selectedIndex = f.selected_search_sources.selectedIndex;
-    selectedValue = f.selected_search_sources.options[selectedIndex].value;
-    <?php endif; ?>
-
-    for (var i = 0; i < searchFields.length; i++) {
-        if (searchFields[i][0] == selectedValue) {
-            for (var j = 1; j < searchFields[i].length; j++) {
-                searchFields[i][j][2] = f.search_fields.options[j - 1].selected;
-            }
-            updateSearchFields();
-            return;
-        }
-    }
-}
-</script>
-
-<br />
-<input type="hidden" name="search_sources" value="<?php echo implode("\t", $selected) ?>" />
-<?php if ($nbReadSources > 1): ?>
-<?php echo _("Choose the order of address books to search when expanding addresses.") ?><br />
-<table>
- <tr>
-  <td>
-   <label for="unselected_search_sources" class="hidden"><?php echo _("Available Address books:") ?></label>
-   <select id="unselected_search_sources" name="unselected_search_sources" multiple="multiple" size="5" style="width:20em" onchange="deselectHeaders()">
-    <option value=""><?php echo _("Available Address books:") ?></option>
-    <?php echo $readSelect ?>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="addSource(); return false;"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'lhand.png' : 'rhand.png', _("Add source")) ?></a>
-   <br />
-   <a href="#" onclick="removeSource(); return false;"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'rhand.png' : 'lhand.png', _("Remove source")) ?></a>
-  </td>
-  <td>
-   <label for="selected_search_sources" class="hidden"><?php echo _("Selected Address books:") ?></label>
-   <select name="selected_search_sources" multiple="multiple" size="5" style="width:20em" onchange="deselectHeaders();updateSearchFields();">
-    <option value=""><?php echo _("Selected Address books:") ?></option>
-    <?php echo $prefSelect ?>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="moveSourceUp(); return false;"><?php echo Horde::img('nav/up.png', _("Move up")) ?></a>
-   <br />
-   <a href="#" onclick="moveSourceDown(); return false;"><?php echo Horde::img('nav/down.png', _("Move down")) ?></a>
-  </td>
- </tr>
-</table>
-
-<?php echo _("Click on one of your selected address books and then select all fields to search.") ?><br />
-<?php else: ?>
-<?php echo _("Select all fields to search when expanding addresses.") ?><br />
-<?php endif; ?>
-
-<?php echo _("To select multiple fields, hold down the Control (PC) or Command (Mac) while clicking.") ?><br />
-<input type="hidden" name="search_fields_string" />
-<table>
- <tr>
-  <td>
-   <label for="search_fields" class="hidden"><?php echo _("Fields to search") ?></label>
-   <select id="search_fields" name="search_fields" multiple="multiple" size="5" style="width:20em" onchange="changeSearchFields()">
-    <option><?php echo str_repeat('&nbsp;', 50) ?></option>
-   </select>
-  </td>
- </tr>
-</table>
-
-<script type="text/javascript">
-updateSearchFields();
-</script>
-<?php endif; ?>
index b539f39..01c60ec 100644 (file)
@@ -1472,6 +1472,15 @@ li.panel-tags {
     display: none;
 }
 
+/* Prefs */
+.fburl {
+    border: 1px solid black;
+    padding: 5px 0 10px 15px;
+}
+.fburl .fixed {
+    padding-top: 3px;
+}
+
 @media print {
     .rowEven td, .rowOdd td {
         background: #fff;
index 9565566..0f3f66d 100644 (file)
@@ -23,113 +23,99 @@ $prefGroups['tasks'] = array(
     'column' => _("General Options"),
     'label' => _("Task Defaults"),
     'desc' => _("Defaults for new tasks"),
-    'members' => array('default_due', 'default_due_days', 'defaultduetimeselect'),
+    'members' => array('default_due', 'default_due_days', 'default_due_time'),
 );
 
 $prefGroups['share'] = array(
     'column' => _("Task List and Share Options"),
     'label' => _("Default Task List"),
     'desc' => _("Choose your default task list."),
-    'members' => array('tasklistselect'),
+    'members' => array('default_tasklist'),
 );
 
 $prefGroups['notification'] = array(
     'column' => _("Task List and Share Options"),
     'label' => _("Notifications"),
     'desc' => _("Choose if you want to be notified of task changes and task alarms."),
-    'members' => array('task_notification'),
-);
-if (!empty($GLOBALS['conf']['alarms']['driver'])) {
-    $prefGroups['notification']['members'][] = 'task_alarms';
-}
-
-$_show_external = array();
-if ($GLOBALS['registry']->hasMethod('getListTypes', 'whups')) {
-    $_show_external['whups'] = $GLOBALS['registry']->get('name', 'whups');
-}
-if (count($_show_external)) {
-    $prefGroups['external'] = array(
-        'column'  => _("Task List and Share Options"),
-        'label'   => _("External Data"),
-        'desc'    => _("Show data from other applications or sources."),
-        'members' => array('show_external'),
-    );
-}
+    'members' => array('task_notification', 'task_alarms'),
+);
+
+$prefGroups['external'] = array(
+    'column'  => _("Task List and Share Options"),
+    'label'   => _("External Data"),
+    'desc'    => _("Show data from other applications or sources."),
+    'members' => array('show_external'),
+);
 
 // columns in the list view
 $_prefs['tasklist_columns'] = array(
     'value' => 'a:3:{i:0;s:8:"priority";i:1;s:3:"due";i:2;s:8:"category";}',
-    'locked' => false,
-    'shared' => false,
     'type' => 'multienum',
-    'enum' => array('tasklist' => _("Task List"),
-                    'priority' => _("Priority"),
-                    'assignee' => _("Assignee"),
-                    'due' => _("Due Date"),
-                    'estimate' => _("Estimated Time"),
-                    'category' => _("Category")),
+    'enum' => array(
+        'tasklist' => _("Task List"),
+        'priority' => _("Priority"),
+        'assignee' => _("Assignee"),
+        'due' => _("Due Date"),
+        'estimate' => _("Estimated Time"),
+        'category' => _("Category")
+    ),
     'desc' => _("Select the columns that should be shown in the list view:")
 );
 
 // show the task list options panel?
 // a value of 0 = no, 1 = yes
 $_prefs['show_panel'] = array(
-    'value' => 1,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => 1
 );
 
 // user preferred sorting column
 $_prefs['sortby'] = array(
     'value' => Nag::SORT_PRIORITY,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(Nag::SORT_PRIORITY => _("Priority"),
-                    Nag::SORT_NAME => _("Task Name"),
-                    Nag::SORT_CATEGORY => _("Category"),
-                    Nag::SORT_DUE => _("Due Date"),
-                    Nag::SORT_COMPLETION => _("Completed?"),
-                    Nag::SORT_ESTIMATE => _("Estimated Time"),
-                    Nag::SORT_ASSIGNEE => _("Assignee"),
-                    Nag::SORT_OWNER => _("Task List")),
+    'enum' => array(
+        Nag::SORT_PRIORITY => _("Priority"),
+        Nag::SORT_NAME => _("Task Name"),
+        Nag::SORT_CATEGORY => _("Category"),
+        Nag::SORT_DUE => _("Due Date"),
+        Nag::SORT_COMPLETION => _("Completed?"),
+        Nag::SORT_ESTIMATE => _("Estimated Time"),
+        Nag::SORT_ASSIGNEE => _("Assignee"),
+        Nag::SORT_OWNER => _("Task List")
+    ),
     'desc' => _("Sort tasks by:"),
 );
 
 // alternate sort column
 $_prefs['altsortby'] = array(
     'value' => Nag::SORT_CATEGORY,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(Nag::SORT_PRIORITY => _("Priority"),
-                    Nag::SORT_NAME => _("Task Name"),
-                    Nag::SORT_CATEGORY => _("Category"),
-                    Nag::SORT_DUE => _("Due Date"),
-                    Nag::SORT_COMPLETION => _("Completed?"),
-                    Nag::SORT_ESTIMATE => _("Estimated Time"),
-                    Nag::SORT_ASSIGNEE => _("Assignee"),
-                    Nag::SORT_OWNER => _("Task List")),
+    'enum' => array(
+        Nag::SORT_PRIORITY => _("Priority"),
+        Nag::SORT_NAME => _("Task Name"),
+        Nag::SORT_CATEGORY => _("Category"),
+        Nag::SORT_DUE => _("Due Date"),
+        Nag::SORT_COMPLETION => _("Completed?"),
+        Nag::SORT_ESTIMATE => _("Estimated Time"),
+        Nag::SORT_ASSIGNEE => _("Assignee"),
+        Nag::SORT_OWNER => _("Task List")
+    ),
     'desc' => _("Then:"),
 );
 
 // user preferred sorting direction
 $_prefs['sortdir'] = array(
     'value' => Nag::SORT_ASCEND,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(Nag::SORT_ASCEND => _("Ascending"),
-                    Nag::SORT_DESCEND => _("Descending")),
+    'enum' => array(
+        Nag::SORT_ASCEND => _("Ascending"),
+        Nag::SORT_DESCEND => _("Descending")
+    ),
     'desc' => _("Sort direction:"),
 );
 
 // preference for delete confirmation dialog.
 $_prefs['delete_opt'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Do you want to confirm deleting entries?"),
 );
@@ -137,8 +123,6 @@ $_prefs['delete_opt'] = array(
 // default to tasks having a due date?
 $_prefs['default_due'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("When creating a new task, should it default to having a due date?"),
 );
@@ -146,8 +130,6 @@ $_prefs['default_due'] = array(
 // default number of days out for due dates
 $_prefs['default_due_days'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("When creating a new task, how many days in the future should the default due date be (0 means today)?"),
 );
@@ -155,85 +137,64 @@ $_prefs['default_due_days'] = array(
 // default due time
 $_prefs['default_due_time'] = array(
     'value' => 'now',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'type' => 'enum',
+    'desc' => _("What do you want to be the default due time for tasks?")
 );
 
-// default due time selection widget
-$_prefs['defaultduetimeselect'] = array('type' => 'special');
-
 // new task notifications
 $_prefs['task_notification'] = array(
     'value' => '',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('' => _("No"),
-                    'owner' => _("On my task lists only"),
-                    'show' => _("On all shown task lists"),
-                    'read' => _("On all task lists I have read access to")),
+    'enum' => array(
+        '' => _("No"),
+        'owner' => _("On my task lists only"),
+        'show' => _("On all shown task lists"),
+        'read' => _("On all task lists I have read access to")
+    ),
     'desc' => _("Choose if you want to be notified of new, edited, and deleted tasks by email:"),
 );
 
 // alarm methods
 $_prefs['task_alarms'] = array(
     'value' => 'a:1:{s:6:"notify";a:0:{}}',
-    'locked' => false,
-    'shared' => false,
     'type' => 'alarm',
     'desc' => _("Choose how you want to receive reminders for tasks with alarms:"),
 );
 
 // show data from other applications that can be listed as tasks?
-if (count($_show_external)) {
-    $_prefs['show_external'] = array(
-        'value' => 'a:0:{}',
-        'locked' => false,
-        'shared' => false,
-        'type' => 'multienum',
-        'enum' => $_show_external,
-        'desc' => _("Show data from any of these other applications in your task list?"),
-    );
-}
+$_prefs['show_external'] = array(
+    'value' => 'a:0:{}',
+    'type' => 'multienum',
+    'desc' => _("Show data from any of these other applications in your task list?"),
+);
 
 // show complete/incomplete tasks?
 $_prefs['show_completed'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(Nag::VIEW_ALL => _("All tasks"),
-                    Nag::VIEW_INCOMPLETE => _("Incomplete tasks"),
-                    Nag::VIEW_COMPLETE => _("Complete tasks"),
-                    Nag::VIEW_FUTURE => _("Future tasks")),
+    'enum' => array(
+        Nag::VIEW_ALL => _("All tasks"),
+        Nag::VIEW_INCOMPLETE => _("Incomplete tasks"),
+        Nag::VIEW_COMPLETE => _("Complete tasks"),
+        Nag::VIEW_FUTURE => _("Future tasks")
+    ),
     'desc' => _("Show complete, incomplete, or all tasks in the task list?"),
 );
 
 // user task categories
 $_prefs['task_categories'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => ''
 );
 
-// default task list selection widget
-$_prefs['tasklistselect'] = array('type' => 'special');
-
 // default tasklists
 // Set locked to true if you don't want users to have multiple task lists.
 $_prefs['default_tasklist'] = array(
     'value' => Horde_Auth::getAuth() ? Horde_Auth::getAuth() : 0,
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'type' => 'enum',
+    'desc' => _("Your default task list:")
 );
 
 // store the task lists to diplay
 $_prefs['display_tasklists'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => 'a:0:{}'
 );
index 4fb0d9f..9a97618 100644 (file)
@@ -92,39 +92,70 @@ class Nag_Application extends Horde_Registry_Application
     }
 
     /**
-     * Special preferences handling on update.
+     * Code to run on init when viewing prefs for this application.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
-     *
-     * @return boolean  True if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsSpecial($item, $updated)
+    public function prefsInit($ui)
     {
-        switch ($item) {
-        case 'tasklistselect':
-            $default_tasklist = Horde_Util::getFormData('default_tasklist');
-            if (!is_null($default_tasklist)) {
-                $tasklists = Nag::listTasklists();
-                if (isset($tasklists[$default_tasklist]) &&
-                    ($tasklists[$default_tasklist]->get('owner') == Horde_Auth::getAuth() ||
-                     in_array($default_tasklist, $GLOBALS['display_tasklists']))) {
-                    $GLOBALS['prefs']->setValue('default_tasklist', $default_tasklist);
-                    return true;
+        global $conf, $prefs, $registry;
+
+        switch ($ui->group) {
+        case 'notification':
+            if (empty($conf['alarms']['driver'])) {
+                $ui->suppress[] = 'task_alarms';
+            }
+            break;
+
+        case 'share':
+            if (!$prefs->isLocked('default_tasklist')) {
+                $all_tasklists = Nag::listTasklists();
+                $tasklists = array();
+
+                foreach ($all_tasklists as $id => $tasklist) {
+                    if (!empty($conf['share']['hidden']) &&
+                        ($tasklist->get('owner') != Horde_Auth::getAuth()) &&
+                        !in_array($tasklist->getName(), $GLOBALS['display_tasklists'])) {
+                        continue;
+                    }
+                    $tasklists[$id] = $tasklist;
+                }
+
+                $vals = array();
+                foreach ($tasklists as $id => $tasklist) {
+                    $vals[htmlspecialchars($id)] = htmlspecialchars($tasklist->get('name'));
                 }
+                $ui->override['default_tasklist'] = $vals;
             }
             break;
 
-        case 'showsummaryselect':
-            $GLOBALS['prefs']->setValue('summary_categories', Horde_Util::getFormData('summary_categories'));
-            return true;
+        case 'tasks':
+            if (!$prefs->isLocked('default_due_time')) {
+                $twentyfour = $prefs->getValue('twentyFour');
 
-        case 'defaultduetimeselect':
-            $GLOBALS['prefs']->setValue('default_due_time', Horde_Util::getFormData('default_due_time'));
-            return true;
+                $vals = array('now' => _("The current hour"));
+                for ($i = 0; $i < 24; ++$i) {
+                    $value = sprintf('%02d:00', $i);
+                    $vals[$value] = ($twentyfour)
+                        ? $value
+                        : sprintf('%02d:00 ' . ($i >= 12 ? _("pm") : _("am")), ($i % 12 ? $i % 12 : 12));
+                }
+                $ui->override['default_due_time'] = $vals;
+            }
+            break;
         }
 
-        return $updated;
+        /* Hide appropriate prefGroups. */
+        $show_external = array();
+        if ($registry->hasMethod('getListTypes', 'whups')) {
+            $show_external['whups'] = $registry->get('name', 'whups');
+        }
+        if (count($show_external)) {
+            $ui->override['show_external'] = $show_external;
+        } else {
+            $ui->suppress[] = 'show_external';
+            $ui->suppresGroups[] = 'external';
+        }
     }
 
     /**
diff --git a/nag/templates/prefs/defaultduetimeselect.inc b/nag/templates/prefs/defaultduetimeselect.inc
deleted file mode 100644 (file)
index 9223d63..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-if (!$prefs->isLocked('default_due_time')):
-    $default_due_time = $prefs->getValue('default_due_time');
-?>
-
-<?php echo Horde::label('default_due_time', _("What do you want to be the default due time for tasks?")) ?><br />
-<select id="default_due_time" name="default_due_time">
- <option value="now"<?php if ($default_due_time == 'now') echo ' selected="selected"' ?>><?php echo _("The current hour") ?></option>
-<?php
-for ($i = 0; $i < 24; ++$i) {
-    $value = sprintf('%02d:00', $i);
-    if ($GLOBALS['prefs']->getValue('twentyFour')) {
-        echo '<option value="' . $value . '"' . ($value == $default_due_time ? ' selected="selected"' : '') . '>' . $value . '</option>';
-    } else {
-        echo '<option value="' . $value . '"' . ($value == $default_due_time ? ' selected="selected"' : '') . '>' . sprintf('%02d:00 ' . ($i >= 12 ? _("pm") : _("am")), ($i % 12 ? $i % 12 : 12)) . '</option>';
-    }
-}
-?>
-</select><br /><br />
-<?php endif; ?>
diff --git a/nag/templates/prefs/tasklistselect.inc b/nag/templates/prefs/tasklistselect.inc
deleted file mode 100644 (file)
index 2d77197..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-if (!$prefs->isLocked('default_tasklist')):
-    $all_tasklists = Nag::listTasklists();
-    $tasklists = array();
-    foreach ($all_tasklists as $id => $tasklist) {
-        if ($tasklist->get('owner') != Horde_Auth::getAuth() &&
-            !empty($GLOBALS['conf']['share']['hidden']) &&
-            !in_array($tasklist->getName(), $GLOBALS['display_tasklists'])) {
-            continue;
-        }
-        $tasklists[$id] = $tasklist;
-    }
-    if (($default_tasklist = $prefs->getValue('default_tasklist')) == null ||
-        !isset($tasklists[$default_tasklist])) {
-        $default_tasklist = Horde_Auth::getAuth();
-    }
-?>
-
-<?php echo Horde::label('default_tasklist', _("Your default task list:")) ?><br />
-<select id="default_tasklist" name="default_tasklist">
-<?php foreach ($tasklists as $id => $tasklist): ?>
-    <option value="<?php echo htmlspecialchars($id) ?>"<?php if ($id == $default_tasklist) echo ' selected="selected"' ?>><?php echo htmlspecialchars($tasklist->get('name')) ?></option>
-<?php endforeach; ?>
-</select><br /><br />
-<?php endif; ?>
index 07a1c90..6e01b49 100644 (file)
@@ -35,7 +35,6 @@ $prefGroups['format'] = array(
 
 // Address Book selection widget
 $_prefs['addressbookselect'] = array(
-    'locked' => false,
     'type' => 'special',
 );
 
@@ -46,25 +45,19 @@ $_prefs['addressbookselect'] = array(
 // double quotes are REQUIRED).  If 'value' is empty (''), all address
 // books that the user has permissions to will be listed.
 $_prefs['addressbooks'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ''
 );
 
 // Address books use for synchronization
 $_prefs['sync_books'] = array(
     'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
     'type' => 'multienum',
     'desc' => _("Select the address books that should be used for synchronization with external devices:"),
 );
 
 // Columns selection widget
 $_prefs['columnselect'] = array(
-    'locked' => false,
-    'type' => 'special',
+    'type' => 'special'
 );
 
 // Columns to be displayed in Browse and Search results, with entries
@@ -73,34 +66,24 @@ $_prefs['columnselect'] = array(
 // currently always displayed first and so cannot be modified here.
 // Double quotes MUST be used as in the example.
 $_prefs['columns'] = array(
-    'value' => "netcenter\temail\nverisign\temail\nlocalsql\temail",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => "netcenter\temail\nverisign\temail\nlocalsql\temail"
 );
 
 // user preferred sorting column
 // serialized array of hashes containing 'field' and 'ascending' keys
 $_prefs['sortorder'] = array(
-    'value' => 'a:1:{i:0;a:2:{s:5:"field";s:8:"lastname";s:9:"ascending";b:1;}}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => 'a:1:{i:0;a:2:{s:5:"field";s:8:"lastname";s:9:"ascending";b:1;}}'
 );
 
 // number of maximum pages and items per page
 $_prefs['maxpage'] = array(
     'value' => 10,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Maximum number of pages"),
 );
 
 $_prefs['perpage'] = array(
     'value' => 20,
-    'locked' => false,
-    'shared' => false,
     'type' => 'number',
     'desc' => _("Number of items per page"),
 );
@@ -108,61 +91,54 @@ $_prefs['perpage'] = array(
 // the page to display.  Either 'browse.php' or 'search.php'
 $_prefs['initial_page'] = array(
     'value' => 'search.php',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'desc' => _("View to display by default:"),
-    'enum' => array('browse.php' => _("Address Book Listing"),
-                    'search.php' => _("Search")),
+    'enum' => array(
+        'browse.php' => _("Address Book Listing"),
+        'search.php' => _("Search")
+    )
 );
 
 // the format to display names.  Either 'last_first' or 'first_last'
 $_prefs['name_format'] = array(
     'value' => 'none',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'desc' => _("Select the format used to <em>display</em> names:"),
-    'enum' => array('last_first' => _("\"Lastname, Firstname\" (ie. Doe, John)"),
-                    'first_last' => _("\"Firstname Lastname\"  (ie. John Doe)"),
-                    'none' => _("no formatting")),
+    'enum' => array(
+        'last_first' => _("\"Lastname, Firstname\" (ie. Doe, John)"),
+        'first_last' => _("\"Firstname Lastname\"  (ie. John Doe)"),
+        'none' => _("no formatting")
+    )
 );
 
 // the format to sort names.  Either 'last_first' or 'first_last'
 $_prefs['name_sort'] = array(
     'value' => 'none',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'desc' => _("Select the format used to <em>sort</em> names:"),
-    'enum' => array('last_first' => _("\"Lastname, Firstname\" (ie. Doe, John)"),
-                    'first_last' => _("\"Firstname Lastname\"  (ie. John Doe)"),
-                    'none' => _("no formatting")),
+    'enum' => array(
+        'last_first' => _("\"Lastname, Firstname\" (ie. Doe, John)"),
+        'first_last' => _("\"Firstname Lastname\"  (ie. John Doe)"),
+        'none' => _("no formatting")
+    )
 );
 
 // Default directory
+// Addressbook list array is dynamically built when prefs screen is displayed
 $_prefs['default_dir'] = array(
     'value' => '',
     // 'value' => 'localsql',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'select',
+    'type' => 'enum',
     'desc' => _("This will be the default address book when adding or importing contacts."),
 );
 
 // preference for holding any preferences-based addressbooks.
 $_prefs['prefbooks'] = array(
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ''
 );
 
 // Personal contact.
 $_prefs['own_contact'] = array(
     // The format is 'source_name;contact_id'.
-    'value' => '',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => ''
 );
index 47c8524..4d770a0 100644 (file)
@@ -759,9 +759,7 @@ $cfgSources['favourites'] = array(
  * IMSP Horde_Share hooks in horde/config/hooks.php.
  */
 // Check that IMSP is configured in Horde but fall through if there is no
-// configuration at all - in case we don't have at least a 3.0.6 Horde
-// install.  (In that case, be sure to change the params array below to suit
-// your needs.
+// configuration at all.
 if (!empty($GLOBALS['conf']['imsp']['enabled']) ||
     !isset($GLOBALS['conf']['imsp']['enabled'])) {
     // First, get the user name to login to IMSP server with.
diff --git a/turba/js/columnprefs.js b/turba/js/columnprefs.js
new file mode 100644 (file)
index 0000000..e19597f
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * Provides the javascript for managing columns.
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var TurbaColumnPrefs = {
+
+    // Vars defaulting to null: cur_source
+
+    updateColumnsPref: function()
+    {
+        $('columns').value = $$('.turba-prefs-cols-panel').collect(this.updateColumnsPref_1.bind(this)).join("\n");
+    },
+
+    updateColumnsPref_1: function(panel)
+    {
+        var c, p = panel.id.replace('turba-prefs-cols-panel-', '');
+        this.cur_source = p;
+        c = panel.select('input[type=checkbox]:checked').collect(this.updateColumnsPref_2.bind(this)).join("\t");
+        if (c) {
+            p += "\t" + c;
+        }
+        return p;
+    },
+
+    updateColumnsPref_2: function(checkbox)
+    {
+        if (checkbox.checked) {
+            return checkbox.id.replace('turba-prefs-cols-' + this.cur_source + '-', '');
+        }
+    },
+
+    clickHandler: function(e)
+    {
+        var elt = e.element();
+        $('turba-prefs-cols-list').select('.active').invoke('removeClassName', 'active');
+        elt.up().addClassName('active');
+        $$('.turba-prefs-cols-panel').invoke('hide');
+        $('turba-prefs-cols-panel-' + elt.readAttribute('sourcename')).show();
+    },
+
+    onDomLoad: function()
+    {
+        $('turba-prefs-cols-columns').select('OL').each(function(ol) {
+            Sortable.create(ol, { onUpdate: this.updateColumnsPref.bind(this) });
+        }, this);
+
+        $('turba-prefs-cols-columns').observe('click', function(e) {
+            if (e.element().match('input[type=checkbox]')) {
+                this.updateColumnsPref();
+            }
+        }.bindAsEventListener(this));
+
+        $('turba-prefs-cols-list').select('A').invoke('observe', 'click', this.clickHandler.bindAsEventListener(this));
+    }
+
+};
+
+document.observe('dom:loaded', TurbaColumnPrefs.onDomLoad.bind(TurbaColumnPrefs));
index e9bbe7a..13960d2 100644 (file)
@@ -158,75 +158,190 @@ class Turba_Application extends Horde_Registry_Application
     }
 
     /**
-     * Code to run when viewing prefs for this application.
+     * Code to run on init when viewing prefs for this application.
      *
-     * @param string $group  The prefGroup name.
-     *
-     * @return array  A list of variables to export to the prefs display page.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
      */
-    public function prefsInit($group)
+    public function prefsInit($ui)
     {
-        $out = array();
+        global $prefs;
+
+        switch ($ui->group) {
+        case 'addressbooks':
+            Horde_Core_Prefs_Ui_Widgets::sourceInit($ui);
+
+            if (!$prefs->isLocked('default_dir')) {
+                $out = array();
+                foreach ($GLOBALS['cfgSources'] as $key => $info) {
+                    $out[$key] = $info['title'];
+                }
+                $ui->override['default_dir'] = $out;
+            }
 
-        /* Assign variables for select lists. */
-        if (!$GLOBALS['prefs']->isLocked('default_dir')) {
-            $out['default_dir_options'] = array();
-            foreach ($GLOBALS['cfgSources'] as $key => $info) {
-                $out['default_dir_options'][$key] = $info['title'];
+            $out = array();
+            foreach (Turba::getAddressBooks() as $key => $curSource) {
+                if (empty($curSource['map']['__uid'])) {
+                    continue;
+                }
+                if (!empty($curSource['browse'])) {
+                    $out[$key] = $curSource['title'];
+                }
+                $sync_books = @unserialize($prefs->getValue('sync_books'));
+                if (empty($sync_books)) {
+                    $prefs->setValue('sync_books', serialize(array(Turba::getDefaultAddressbook())));
+                }
             }
+            $ui->override['sync_books'] = $out;
+            break;
+
+        case 'columns':
+            Horde::addScriptFile('effects.js', 'horde');
+            Horde::addScriptFile('dragdrop.js', 'horde');
+            Horde::addScriptFile('columnprefs.js', 'turba');
+            break;
         }
+    }
 
-        $out['sync_books_options'] = array();
-        foreach (Turba::getAddressBooks() as $key => $curSource) {
-            if (empty($curSource['map']['__uid'])) {
-                continue;
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    public function prefsSpecial($ui, $item)
+    {
+        switch ($item) {
+        case 'addressbookselect':
+            $order = Turba::getAddressBookOrder();
+            $selected = $sorted = $unselected = array();
+
+            foreach (array_keys($GLOBALS['cfgSources']) as $val) {
+                if (isset($order[$val])) {
+                    $sorted[intval($order[$val])] = $val;
+                } else {
+                    $unselected[$val] = $GLOBALS['cfgSources'][$val]['title'];
+                }
             }
-            if (!empty($curSource['browse'])) {
-                $out['sync_books_options'][$key] = $curSource['title'];
+
+            foreach ($sorted as $val) {
+                $selected[$val] = $GLOBALS['cfgSources'][$val]['title'];
+            }
+
+            return Horde_Core_Prefs_Ui_Widgets::source($ui, array(
+                'mainlabel' => _("Choose which address books to display, and in what order:"),
+                'selected' => $selected,
+                'selectlabel' => _("These addressbooks will display in this order:"),
+                'unselected' => $unselected,
+                'unselectlabel' => _("Address books that will not be displayed:")
+            ));
+
+        case 'columnselect':
+            $sources = Turba::getColumns();
+
+            $t = $GLOBALS['injector']->createInstance('Horde_Template');
+            $t->setOption('gettext', true);
+
+            $t->set('columns', htmlspecialchars($GLOBALS['prefs']->getValue('columns')));
+
+            $col_list = $cols = array();
+            foreach ($GLOBALS['cfgSources'] as $source => $info) {
+                $col_list[] = array(
+                    'first' => empty($col_list),
+                    'source' => htmlspecialchars($source),
+                    'title' => htmlspecialchars($info['title'])
+                );
+
+                // First the selected columns in their current order.
+                $i = 0;
+                $inputs = array();
+
+                if (isset($sources[$source])) {
+                    $selected = array_flip($sources[$source]);
+                    foreach ($sources[$source] as $column) {
+                        if ((substr($column, 0, 2) == '__') ||
+                            ($column == 'name')) {
+                            continue;
+                        }
+
+                        $inputs[] = array(
+                            'checked' => isset($selected[$column]),
+                            'column' => htmlspecialchars($column),
+                            'i' => $i,
+                            'label' => htmlspecialchars($GLOBALS['attributes'][$column]['label'])
+                        );
+                    }
+                } else {
+                    // Need to unset this for the loop below, otherwise
+                    // selected columns from another source could interfere
+                    unset($selected);
+                }
+
+                // Then the unselected columns in source order.
+                foreach (array_keys($info['map']) as $column) {
+                    if ((substr($column, 0, 2) == '__') ||
+                        ($column == 'name') ||
+                        isset($selected[$column])) {
+                        continue;
+                    }
+
+                    $inputs[] = array(
+                        'checked' => isset($selected[$column]),
+                        'column' => htmlspecialchars($column),
+                        'i' => $i,
+                        'label' => htmlspecialchars($GLOBALS['attributes'][$column]['label'])
+                    );
+                }
+
+                $cols[] = array(
+                    'first' => empty($cols),
+                    'inputs' => $inputs,
+                    'source' => htmlspecialchars($source)
+                );
             }
-            $sync_books = @unserialize($GLOBALS['prefs']->getValue('sync_books'));
-            if (empty($sync_books)) {
-                $GLOBALS['prefs']->setValue('sync_books', serialize(array(Turba::getDefaultAddressbook())));
+
+            if (!empty($col_list)) {
+                $t->set('col_list', $col_list);
+                $t->set('cols', $cols);
             }
-        }
 
-        return $out;
+            return $t->fetch(TURBA_TEMPLATES . '/prefs/column.html');
+        }
     }
 
     /**
      * Special preferences handling on update.
      *
-     * @param string $item      The preference name.
-     * @param boolean $updated  Set to true if preference was updated.
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
      *
      * @return boolean  True if preference was updated.
      */
-    public function prefsSpecial($item, $updated)
+    public function prefsSpecialUpdate($ui, $item)
     {
         switch ($item) {
+        case 'addressbookselect':
+            $ui->setValue('addressbooks', Horde_Serialize::unserialize($ui->vars->sources, Horde_Serialize::JSON));
+            return true;
+
         case 'columnselect':
-            $columns = Horde_Util::getFormData('columns');
-            if (!empty($columns)) {
-                $GLOBALS['prefs']->setValue('columns', $columns);
+            if (isset($ui->vars->columns)) {
+                $ui->setValue('columns', $ui->vars->columns);
                 return true;
             }
             break;
-
-        case 'addressbookselect':
-            $addressbooks = Horde_Util::getFormData('addressbooks');
-            $GLOBALS['prefs']->setValue('addressbooks', str_replace("\r", '', $addressbooks));
-            return true;
         }
-
-        return $updated;
     }
 
     /**
      * Generate the menu to use on the prefs page.
      *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     *
      * @return Horde_Menu  A Horde_Menu object.
      */
-    public function prefsMenu()
+    public function prefsMenu($ui)
     {
         return Turba::getMenu();
     }
@@ -284,7 +399,8 @@ class Turba_Application extends Horde_Registry_Application
                 }
             }
 
-            /* Get a list of all shares this user has perms to and remove the perms */
+            /* Get a list of all shares this user has perms to and remove the
+             * perms. */
             $shares = $GLOBALS['turba_shares']->listShares($user);
             if (is_a($shares, 'PEAR_Error')) {
                 Horde::logMessage($shares, 'ERR');
diff --git a/turba/templates/prefs/addressbookselect.inc b/turba/templates/prefs/addressbookselect.inc
deleted file mode 100644 (file)
index 37b6deb..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-<?php
-
-$order = Turba::getAddressBookOrder();
-$js = "var addressbooks = [];\n";
-$source_count = 0;
-foreach ($GLOBALS['cfgSources'] as $source => $info) {
-    $selected = isset($order[$source]) ? 'true' : 'false';
-    $js .= "addressbooks[$source_count] = ['" . addslashes($source) . "', decodeURIComponent('" . rawurlencode($info['title']) . "'), $selected, " . (isset($order[$source]) ? (int)$order[$source] : 'null') . "];\n";
-    $source_count++;
-}
-
-if (!$prefs->isLocked('addressbooks') && $source_count):
-?>
-
-<script type="text/javascript">
-<!--
-<?php echo $js ?>
-
-function selectAddressBooks()
-{
-    var selected = [];
-    var unselected = [];
-    for (var i = 0; i < addressbooks.length; i++) {
-        if (addressbooks[i][2]) {
-            selected[addressbooks[i][3]] = [addressbooks[i][1], addressbooks[i][0]];
-        } else {
-            unselected[unselected.length] = [addressbooks[i][1], addressbooks[i][0]];
-        }
-    }
-    for (i = 0; i < selected.length; i++) {
-        f.selected_addressbooks.options[i + 1] = new Option(selected[i][0], selected[i][1]);
-    }
-    for (i = 0; i < unselected.length; i++) {
-        f.unselected_addressbooks.options[i + 1] = new Option(unselected[i][0], unselected[i][1]);
-    }
-}
-
-function deselectHeaders()
-{
-    document.prefs.unselected_addressbooks[0].selected = false;
-    document.prefs.selected_addressbooks[0].selected = false;
-}
-
-function resetHidden()
-{
-    var tmp = '';
-    for (var i = 1; i < f.selected_addressbooks.length; i++) {
-        if (tmp != '') {
-            tmp += '\n';
-        }
-        tmp += f.selected_addressbooks[i].value;
-    }
-    document.prefs.addressbooks.value = tmp;
-}
-
-function addAddressBook()
-{
-    for (i = 1; i < f.unselected_addressbooks.length; i++) {
-        if (f.unselected_addressbooks[i].selected) {
-            f.selected_addressbooks[f.selected_addressbooks.length] = new Option(f.unselected_addressbooks[i].text, f.unselected_addressbooks[i].value);
-            f.unselected_addressbooks[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function removeAddressBook()
-{
-    for (i = 1; i < f.selected_addressbooks.length; i++) {
-        if (f.selected_addressbooks[i].selected) {
-            f.unselected_addressbooks[f.unselected_addressbooks.length] = new Option(f.selected_addressbooks[i].text, f.selected_addressbooks[i].value)
-            f.selected_addressbooks[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function moveAddressBookUp()
-{
-    var sel = f.selected_addressbooks.selectedIndex;
-
-    if (sel <= 1 || f.selected_addressbooks.length <= 2) return;
-
-    // deselect everything but the first selected item
-    f.selected_addressbooks.selectedIndex = sel;
-    var up = f.selected_addressbooks[sel].value;
-
-    tmp = [];
-    for (i = 1; i < f.selected_addressbooks.length; i++) {
-        tmp[i - 1] = new Option(f.selected_addressbooks[i].text, f.selected_addressbooks[i].value)
-    }
-
-    for (i = 0; i < tmp.length; i++) {
-        if (i + 1 == sel - 1) {
-            f.selected_addressbooks[i + 1] = tmp[i + 1];
-        } else if (i + 1 == sel) {
-            f.selected_addressbooks[i + 1] = tmp[i - 1];
-        } else {
-            f.selected_addressbooks[i + 1] = tmp[i];
-        }
-    }
-
-    f.selected_addressbooks.selectedIndex = sel - 1;
-
-    for (i = 2; i < addressbooks.length - 1; i++) {
-        if (addressbooks[i][0] == up) {
-            addressbook = addressbooks[i];
-            addressbooks[i] = addressbooks[i - 1];
-            addressbooks[i - 1] = addressbook;
-        }
-    }
-
-    resetHidden();
-}
-
-function moveAddressBookDown()
-{
-    var sel = f.selected_addressbooks.selectedIndex;
-
-    if (sel == -1 || f.selected_addressbooks.length <= 2 || sel == f.selected_addressbooks.length - 1) return;
-
-    // deselect everything but the first selected item
-    f.selected_addressbooks.selectedIndex = sel;
-    var down = f.selected_addressbooks[sel].value;
-
-    tmp = [];
-    for (i = 1; i < f.selected_addressbooks.length; i++) {
-        tmp[i - 1] = new Option(f.selected_addressbooks[i].text, f.selected_addressbooks[i].value)
-    }
-
-    for (i = 0; i < tmp.length; i++) {
-        if (i + 1 == sel) {
-            f.selected_addressbooks[i + 1] = tmp[i + 1];
-        } else if (i + 1 == sel + 1) {
-            f.selected_addressbooks[i + 1] = tmp[i - 1];
-        } else {
-            f.selected_addressbooks[i + 1] = tmp[i];
-        }
-    }
-
-    f.selected_addressbooks.selectedIndex = sel + 1;
-
-    for (i = addressbooks.length - 2; i > 0; i--) {
-        if (addressbooks[i][0] == down || addressbooks[i + 1][0] == down) {
-            addressbook = addressbooks[i];
-            addressbooks[i] = addressbooks[i + 1];
-            addressbooks[i + 1] = addressbook;
-        }
-    }
-
-    resetHidden();
-}
-
-// -->
-</script>
-
-<input type="hidden" name="addressbooks" value="<?php echo htmlspecialchars($prefs->getValue('addressbooks')) ?>" />
-
-<?php echo _("Choose which address books to display, and in what order:") ?><br />
-<table>
- <tr>
-  <td>
-   <label for="unselected_addressbooks" class="hidden"><?php echo _("Address books that will not be displayed:") ?></label>
-   <select id="unselected_addressbooks" name="unselected_addressbooks" multiple="multiple" size="5" style="width:300px" onchange="deselectHeaders();">
-    <option class="control" value=""><?php echo _("Address books that will not be displayed:") ?></option>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="addAddressBook(); return false;"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'lhand.png' : 'rhand.png', _("Add address book")) ?></a>
-   <br />
-   <a href="#" onclick="removeAddressBook(); return false;"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'rhand.png' : 'lhand.png', _("Remove address book")) ?></a>
-  </td>
-  <td>
-   <label for="selected_addressbooks" class="hidden"><?php echo _("These address books will display in this order:") ?></label>
-   <select id="selected_addressbooks" name="selected_addressbooks" multiple="multiple" size="5" style="width:300px" onchange="deselectHeaders();">
-    <option class="control" value=""><?php echo _("These address books will display in this order:") ?></option>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="moveAddressBookUp(); return false;"><?php echo Horde::img('nav/up.png', _("Move left")) ?></a>
-   <br />
-   <a href="#" onclick="moveAddressBookDown(); return false;"><?php echo Horde::img('nav/down.png', _("Move right")) ?></a>
-  </td>
- </tr>
-</table>
-<script type="text/javascript">
-<!--
-var f = document.prefs;
-selectAddressBooks();
-// -->
-</script>
-
-<?php endif; // End if not locked && address books exist.
diff --git a/turba/templates/prefs/column.html b/turba/templates/prefs/column.html
new file mode 100644 (file)
index 0000000..30e1ab3
--- /dev/null
@@ -0,0 +1,33 @@
+<input type="hidden" name="columns" id="columns" value="<tag:columns />" />
+
+<if:col_list>
+
+<div id="turba-prefs-cols-container">
+ <p><gettext>Click an address book to sort its columns. Drag columns to re-arrange them. Check a column to enable it.</gettext></p>
+
+ <div id="turba-prefs-cols-list">
+  <ul>
+<loop:col_list>
+   <li<if:col_list.first> class="active"</if:col_list.first>><a href="#" sourcename="<tag:col_list.source />"><tag:col_list.title /></a></li>
+</loop:col_list>
+  </ul>
+ </div>
+
+ <div id="turba-prefs-cols-columns">
+<loop:cols>
+  <div class="turba-prefs-cols-panel" id="turba-prefs-cols-panel-<tag:cols.source />" style="display:<if:cols.first>block<else:cols.first>none</else:cols.first></if:cols.first>;">
+   <ol id="turba-prefs-<tag:cols.source />">
+<loop:cols.inputs>
+    <li id="turba-prefs-cols-<tag:cols.source />_<tag:cols.inputs.i />">
+     <input name="turba-prefs-cols-<tag:cols.source />-<tag:cols.inputs.column />" id="turba-prefs-cols-<tag:cols.source />-<tag:cols.inputs.column />" type="checkbox" class="checkbox"<if:cols.inputs.checked> checked="checked"</if:cols.inputs.checked> /><tag:cols.inputs.label />
+    </li>
+</loop:cols.inputs>
+   </ol>
+  </div>
+</loop:cols>
+ </div>
+
+ <br class="clear" />
+
+</div>
+</if:col_list>
diff --git a/turba/templates/prefs/columnselect.inc b/turba/templates/prefs/columnselect.inc
deleted file mode 100644 (file)
index 8301b01..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php if (!$prefs->isLocked('columns')):
-
-Horde::addScriptFile('effects.js', 'horde');
-Horde::addScriptFile('dragdrop.js', 'horde');
-
-global $cfgSources, $attributes;
-$sources = Turba::getColumns();
-
-?>
-
-<script type="text/javascript">
-var cur_source;
-function updateColumnsPref()
-{
-    $('columns').value = $$('.turba-prefs-cols-panel').collect(updateColumnsPref_1).join("\n");
-}
-function updateColumnsPref_1(panel)
-{
-    var p = panel.id.replace('turba-prefs-cols-panel-', '');
-    cur_source = p;
-    var c = panel.select('input[type=checkbox]:checked').collect(updateColumnsPref_2).join("\t");
-    if (c) {
-        p += "\t" + c;
-    }
-    return p;
-}
-function updateColumnsPref_2(checkbox)
-{
-    if (checkbox.checked) {
-        return checkbox.id.replace('turba-prefs-cols-' + cur_source + '-', '');
-    }
-}
-</script>
-
-<input type="hidden" name="columns" id="columns" value="<?php echo htmlspecialchars($prefs->getValue('columns')) ?>" />
-
-<?php if (count($cfgSources) > 0): ?>
-
-<div id="turba-prefs-cols-container">
-<?php echo _("Click an address book to sort its columns. Drag columns to re-arrange them. Check a column to enable it.") ?><br /><br />
-
-<div id="turba-prefs-cols-list">
- <ul>
-  <?php $first = true; foreach ($cfgSources as $key => $info): ?>
-  <li<?php if ($first) echo ' class="active"'; $first = false; ?>><a href="#" onclick="$$('#turba-prefs-cols-list .active').invoke('removeClassName', 'active'); $(this).up().addClassName('active'); $$('.turba-prefs-cols-panel').invoke('hide'); $('turba-prefs-cols-panel-' + this.readAttribute('sourcename')).show();" sourcename="<?php echo htmlspecialchars($key) ?>"><?php echo htmlspecialchars($info['title']) ?></a></li>
-  <?php endforeach; ?>
- </ul>
-</div>
-
- <div id="turba-prefs-cols-columns">
-
- <?php $first = true; foreach ($cfgSources as $source => $info): ?>
-  <div class="turba-prefs-cols-panel" id="turba-prefs-cols-panel-<?php echo htmlspecialchars($source) ?>" style="display:<?php echo ($first ? 'block' : 'none'); $first = false; ?>;">
-   <ol id="turba-prefs-<?php echo htmlspecialchars($source) ?>">
-<?php
-
-// First the selected columns in their current order.
-$i = 0;
-if (isset($sources[$source])) {
-    $selected = array_flip($sources[$source]);
-    foreach ($sources[$source] as $column) {
-        if (substr($column, 0, 2) == '__' || $column == 'name') {
-            continue;
-        }
-        $checked = isset($selected[$column]) ? ' checked="checked"' : '';
-        $name = htmlspecialchars('turba-prefs-cols-' . $source . '-' . $column);
-        echo '<li id="turba-prefs-cols-' . htmlspecialchars($source) . '_'
-            . $i . '"><input name="' . $name . '" id="' . $name
-            . '" type="checkbox" class="checkbox"' . $checked . ' />'
-            . htmlspecialchars($attributes[$column]['label']) . '</li>';
-        $i++;
-    }
-} else {
-    // Need to unset this for the loop below, otherwise selected columns from
-    // another source could interfere
-    unset($selected);
-}
-
-// Then the unselected columns in source order.
-foreach (array_keys($info['map']) as $column) {
-    if (substr($column, 0, 2) == '__' || $column == 'name' ||
-        isset($selected[$column])) {
-        continue;
-    }
-    $checked = isset($selected[$column]) ? ' checked="checked"' : '';
-    $name = htmlspecialchars('turba-prefs-cols-' . $source . '-' . $column);
-    echo '<li id="turba-prefs-cols-' . htmlspecialchars($source) . '_' . $i
-        . '"><input name="' . $name . '" id="' . $name
-        . '" type="checkbox" class="checkbox"' . $checked . ' />'
-        . htmlspecialchars($attributes[$column]['label']) . '</li>';
-    $i++;
-}
-?>
-   </ol>
-   <script type="text/javascript">
-   Sortable.create('turba-prefs-<?php echo htmlspecialchars($source, ENT_QUOTES) ?>', { onUpdate: updateColumnsPref });
-   </script>
-  </div>
- <?php endforeach; ?>
-</div>
-
-<br class="clear" />
-
-</div>
-
-<?php if ($browser->isBrowser('msie') && $browser->getMajor() < 7): ?>
-<div style="clear:both;">&nbsp;</div>
-<?php endif; ?>
-
-<script type="text/javascript">
-$('turba-prefs-cols-columns').observe('click', function(event) {
-    if (event.element().match('input[type=checkbox]')) {
-        updateColumnsPref();
-    }
-});
-</script>
-
-<?php
-endif; // End form elements when at least 1 source.
-endif; // End prefs UI if not locked.
diff --git a/turba/templates/prefs/imsp_opt.inc b/turba/templates/prefs/imsp_opt.inc
deleted file mode 100644 (file)
index a10d8c1..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-if (!$prefs->isLocked('imsp_opt')):
-    global $cfgSources;
-    $source_count = 0;
-    $imsp_souces = array();
-
-    foreach ($cfgSources as $key => $value) {
-        if (($value['type'] == 'imsp') && (!$value['params']['is_root']) &&
-            (strpos($value['params']['my_rights'], 'd') != false)) {
-            $source_count++;
-            $imsp_sources[$key] = $value;
-        }
-    }
-
-?>
-<script type="text/javascript">
-<!--
-function showAlert()
-{
-    if (document.prefs.imsp_books_delete.value != 'none') {
-        window.alert('<?php echo addslashes(_("Once you save this option page, the address book will be permanently deleted. If this is not what you want, then you must change your selection to \"None\".")) ?>');
-    }
-}
-//-->
-</script>
-<table>
- <tr>
-  <td><?php echo Horde::label('imsp_books_delete', _(" Delete IMSP Address Book")) ?></td>
-  <td>
-   <select id="imsp_books_delete" name="imsp_books_delete" style="width:200px" onchange="showAlert();">
-    <option value="none"><?php echo _("none") ?></option>
-    <?php foreach ($imsp_sources as $key => $value): ?>
-    <option value="<?php echo htmlspecialchars($key) ?>"><?php echo htmlspecialchars($value['title']) ?></option>
-    <?php endforeach ?>
-   </select>
-  </td>
- </tr>
- <tr>
-  <td><?php echo Horde::label('imsp_name', _(" Add an IMSP Address Book")) ?></td>
-  <td><input id="imsp_name" name="imsp_name" type="text" style="width:200px" /></td>
- </tr>
-</table>
-<?php endif; ?>
index b100558..32cae07 100644 (file)
@@ -1,13 +1,19 @@
 <?php
 /**
  * See horde/config/prefs.php for documentation on the structure of this file.
+ *
+ * $Id$
  */
 
 $prefGroups['display'] = array(
     'column' => _("General Options"),
     'label' => _("Display Options"),
     'desc' => _("Change display options such as how search results are sorted."),
-    'members' => array('sortby', 'sortdir', 'comment_sort_dir', 'whups_default_view', 'summary_show_requested', 'summary_show_ticket_numbers', 'report_time_format', 'autolink_tickets')
+    'members' => array(
+        'sortby', 'sortdir', 'comment_sort_dir', 'whups_default_view',
+        'summary_show_requested', 'summary_show_ticket_numbers',
+        'report_time_format', 'autolink_tickets'
+    )
 );
 
 $prefGroups['notification'] = array(
@@ -16,71 +22,64 @@ $prefGroups['notification'] = array(
     'desc' => _("Change options for email notifications of ticket activity."),
     'members' => array('email_others_only', 'email_comments_only'));
 
-if ($GLOBALS['registry']->hasMethod('contacts/sources')) {
-    $prefGroups['addressbooks'] = array(
-        'column' => _("General Options"),
-        'label' => _("Address Books"),
-        'desc' => _("Select address book sources for adding and searching for addresses."),
-        'members' => array('sourceselect'),
-    );
-}
+$prefGroups['addressbooks'] = array(
+    'column' => _("General Options"),
+    'label' => _("Address Books"),
+    'desc' => _("Select address book sources for adding and searching for addresses."),
+    'members' => array('sourceselect'),
+);
 
 
 // the layout of the bugs portal.
 $_prefs['mybugs_layout'] = array(
-    'value' => 'a:0:{}',
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => 'a:0:{}'
 );
 
 // user preferred sorting column
 $_prefs['sortby'] = array(
     'value' => 'id',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('id' => _("Id"),
-                    'summary' => _("Summary"),
-                    'state_name' => _("State"),
-                    'type_name'     => _("Type"),
-                    'priority_name' => _("Priority"),
-                    'queue_name' => _("Queue"),
-                    'version_name' => _("Version"),
-                    'timestamp' => _("Created"),
-                    'date_assigned' => _("Assigned"),
-                    'date_resolved' => _("Resolved")),
+    'enum' => array(
+        'id' => _("Id"),
+        'summary' => _("Summary"),
+        'state_name' => _("State"),
+        'type_name'     => _("Type"),
+        'priority_name' => _("Priority"),
+        'queue_name' => _("Queue"),
+        'version_name' => _("Version"),
+        'timestamp' => _("Created"),
+        'date_assigned' => _("Assigned"),
+        'date_resolved' => _("Resolved")
+    ),
     'desc' => _("Default sorting criteria:")
 );
 
 // user preferred sorting direction
 $_prefs['sortdir'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array(0 => _("Ascending"),
-                    1 => _("Descending")),
+    'enum' => array(
+        0 => _("Ascending"),
+        1 => _("Descending")
+    ),
     'desc' => _("Default sorting direction:")
 );
 
 // default view
 $_prefs['whups_default_view'] = array(
     'value' => 'mybugs',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'enum' => array('mybugs' => _("My Tickets"),
-                    'search' => _("Search Tickets"),
-                    'ticket/create' => _("Create Ticket")),
+    'enum' => array(
+        'mybugs' => _("My Tickets"),
+        'search' => _("Search Tickets"),
+        'ticket/create' => _("Create Ticket")
+    ),
     'desc' => _("Select the view to display after login:")
 );
 
 // show requested tickets in the horde summary?
 $_prefs['summary_show_requested'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show tickets you have requested in the summary view?"),
 );
@@ -88,8 +87,6 @@ $_prefs['summary_show_requested'] = array(
 // show ticket ids in the horde summary?
 $_prefs['summary_show_ticket_numbers'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show ticket IDs in the summary view?"),
 );
@@ -97,8 +94,6 @@ $_prefs['summary_show_ticket_numbers'] = array(
 // Allow custom time/date formats in reports
 $_prefs['report_time_format'] = array(
     'value' => '%m/%d/%y',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         '%a %d %B' => _("Weekday Day Month"),
@@ -116,8 +111,6 @@ $_prefs['report_time_format'] = array(
 // Skip notification of changes you added?
 $_prefs['email_others_only'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Only notify me of ticket changes from other users?"),
 );
@@ -125,8 +118,6 @@ $_prefs['email_others_only'] = array(
 // Skip notification without comments?
 $_prefs['email_comments_only'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Only notify me of ticket changes with comments?")
 );
@@ -134,8 +125,6 @@ $_prefs['email_comments_only'] = array(
 // AutoLink to tickets references in comments
 $_prefs['autolink_tickets'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Autolink to other tickets in comments?")
 );
@@ -143,12 +132,12 @@ $_prefs['autolink_tickets'] = array(
 // Show ticket comments in ascending or descending order?
 $_prefs['comment_sort_dir'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
-    'desc' => _("Show comments in chronological order, or most recent first?"),
-    'enum' => array(0 => _("Chronological (oldest first)"),
-                    1 => _("Most recent first"))
+    'enum' => array(
+        0 => _("Chronological (oldest first)"),
+        1 => _("Most recent first")
+    ),
+    'desc' => _("Show comments in chronological order, or most recent first?")
 );
 
 // address book selection widget
@@ -159,10 +148,7 @@ $_prefs['sourceselect'] = array('type' => 'special');
 // 'value' => "source_one\tsource_two"
 // refer to turba/config/sources.php for possible source values
 $_prefs['search_sources'] = array(
-    'value' => "",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ""
 );
 
 // field(s) to use when expanding addresses
@@ -173,8 +159,5 @@ $_prefs['search_sources'] = array(
 // 'field_three' in source_two.
 // refer to turba/config/sources.php for possible source and field values
 $_prefs['search_fields'] = array(
-    'value' => "",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit',
+    'value' => ""
 );
index ba52370..aa18dbb 100644 (file)
@@ -122,4 +122,61 @@ class Whups_Application extends Horde_Registry_Application
         return $perms;
     }
 
+    /**
+     * Code to run on init when viewing prefs for this application.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    public function prefsInit($ui)
+    {
+        switch ($ui->group) {
+        case 'addressbooks':
+            Horde_Core_Prefs_Ui_Widgets::addressbooksInit($ui);
+            break;
+        }
+
+        if (!$GLOBALS['registry']->hasMethod('contacts/sources')) {
+            $ui->suppressGroups[] = 'addressbooks';
+        }
+    }
+
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    public function prefsSpecial($ui, $item)
+    {
+        switch ($item) {
+        case 'sourceselect':
+            return Horde_Core_Prefs_Ui_Widgets::addressbooks($ui);
+        }
+
+        return '';
+    }
+
+    /**
+     * Special preferences handling on update.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return boolean  True if preference was updated.
+     */
+    public function prefsSpecialUpdate($ui, $item)
+    {
+        $updated = false;
+
+        switch ($item) {
+        case 'sourceselect':
+            $updated = Horde_Core_Prefs_Ui_Widgets::addressbooksUpdate($ui);
+            break;
+        }
+
+        return $updated;
+    }
+
 }
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/whups/templates/prefs/sourceselect.inc b/whups/templates/prefs/sourceselect.inc
deleted file mode 100644 (file)
index a2b2bd9..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-<?php
-if ($registry->hasMethod('contacts/sources')) {
-    $selected = explode("\t", $prefs->getValue('search_sources'));
-    $readable = $registry->call('contacts/sources');
-    $writeable = $registry->call('contacts/sources', true);
-
-    $nbReadSources = count(array_keys($readable));
-    $nbWriteSources = count(array_keys($writeable));
-
-    if (count($selected) == 1 && empty($selected[0])) {
-        $selected = array();
-    }
-
-    if ($nbReadSources == 1) {
-        // Only one source, no need to display the selection widget
-        $selected = array_keys($readable);
-        $readSelect = '';
-    }
-
-    $prefSelect = '';
-    foreach ($selected as $source) {
-        if (!empty($readable[$source])) {
-            $prefSelect .= '<option value="' . $source . '">' . $readable[$source] . "</option>\n";
-        }
-    }
-
-    $readSelect = '';
-    if (!is_a($readable, 'PEAR_Error') && is_array($readable)) {
-        foreach (array_diff(array_keys($readable), $selected) as $source) {
-            $readSelect .= '<option value="' . $source . '">' . $readable[$source] . "</option>\n";
-        }
-    }
-
-    if (!is_a($writeable, 'PEAR_Error') && is_array($writeable)) {
-        $writeSelect = '<option value="">' . _("None") . '</option>' . "\n";
-        $writeSource = '';
-        foreach ($writeable as $source => $name) {
-            $sel = $prefs->getValue('add_source') == $source ? ' selected="selected"' : '';
-            $writeSelect .= '<option value="' . $source . '"' . "$sel>" . $name . "</option>\n";
-            $writeSource = $source;
-        }
-    }
-
-    $selected_fields = array();
-    $search_field_pref = $prefs->getValue('search_fields');
-    if (!empty($search_field_pref)) {
-        $selected_fields = explode("\n", $prefs->getValue('search_fields'));
-        foreach ($selected_fields as $field) {
-            $field = trim($field);
-            if (!empty($field)) {
-                $tmp = explode("\t", $field);
-                if (count($tmp) > 1) {
-                    $source = array_splice($tmp, 0, 1);
-                    $selected_fields[$source[0]] = $tmp;
-                }
-            }
-        }
-    }
-
-    $search_fields = array();
-    if (!is_a($readable, 'PEAR_Error') && is_array($readable)) {
-        foreach (array_keys($readable) as $source) {
-            $search_fields[$source] = $registry->call('contacts/fields', $source);
-        }
-    }
-
-    $js = "var searchFields = [];\n";
-    $source_count = 0;
-    foreach ($search_fields as $source => $fields) {
-        $js .= "searchFields[$source_count] = [];\n";
-        $js .= "searchFields[$source_count][0] = '$source';\n";
-
-        $field_count = 1;
-        foreach ($fields as $field) {
-            if ($field['search']) {
-                $marked = isset($selected_fields[$source]) && in_array($field['name'], $selected_fields[$source]) ? 'true' : 'false';
-                $js .= "searchFields[$source_count][$field_count] = ['" . $field['name'] . "', '" . $field['label'] . "', $marked];\n";
-                $field_count++;
-            }
-        }
-
-        $source_count++;
-    }
-}
-?>
-
-<?php if (!$prefs->isLocked('search_sources') && (!empty($readSelect) || !empty($prefSelect))): ?>
-<script type="text/javascript">
-function deselectHeaders()
-{
-    document.prefs.unselected_search_sources[0].selected = false;
-    document.prefs.selected_search_sources[0].selected = false;
-}
-
-function resetHidden()
-{
-    var tmp = '';
-    for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-        tmp += document.prefs.selected_search_sources[i].value;
-        if (i < document.prefs.selected_search_sources.length - 1)
-            tmp += "\t";
-    }
-
-    document.prefs.search_sources.value = tmp;
-}
-
-function addSource()
-{
-    for (i = 1; i < document.prefs.unselected_search_sources.length; i++) {
-        if (document.prefs.unselected_search_sources[i].selected) {
-            document.prefs.selected_search_sources[document.prefs.selected_search_sources.length] = new Option(document.prefs.unselected_search_sources[i].text, document.prefs.unselected_search_sources[i].value);
-            document.prefs.unselected_search_sources[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function removeSource()
-{
-    for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-        if (document.prefs.selected_search_sources[i].selected) {
-            document.prefs.unselected_search_sources[document.prefs.unselected_search_sources.length] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-            document.prefs.selected_search_sources[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function moveSourceUp()
-{
-    var sel = document.prefs.selected_search_sources.selectedIndex;
-
-    if (sel == -1 || document.prefs.selected_search_sources.length <= 2) return;
-
-    // deselect everything but the first selected item
-    document.prefs.selected_search_sources.selectedIndex = sel;
-
-    if (sel == 1) {
-        tmp = document.prefs.selected_search_sources[sel];
-        document.prefs.selected_search_sources[sel] = null;
-        document.prefs.selected_search_sources[document.prefs.selected_search_sources.length] = tmp;
-        document.prefs.selected_search_sources.selectedIndex = document.prefs.selected_search_sources.length - 1;
-    } else {
-        tmp = [];
-        for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-            tmp[i - 1] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-        }
-
-        for (i = 0; i < tmp.length; i++) {
-            if (i + 1 == sel - 1) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i + 1];
-            } else if (i + 1 == sel) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i - 1];
-            } else {
-                document.prefs.selected_search_sources[i + 1] = tmp[i];
-            }
-        }
-
-        document.prefs.selected_search_sources.selectedIndex = sel - 1;
-    }
-
-    resetHidden();
-}
-
-function moveSourceDown()
-{
-    var sel = document.prefs.selected_search_sources.selectedIndex;
-
-    if (sel == -1 || document.prefs.selected_search_sources.length <= 2) return;
-
-    // deselect everything but the first selected item
-    document.prefs.selected_search_sources.selectedIndex = sel;
-
-    if (sel == document.prefs.selected_search_sources.length - 1) {
-        tmp = [];
-        for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-            tmp[i - 1] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-        }
-
-        document.prefs.selected_search_sources[1] = tmp[tmp.length - 1];
-        for (i = 0; i < tmp.length - 1; i++) {
-            document.prefs.selected_search_sources[i + 2] = tmp[i];
-        }
-
-        document.prefs.selected_search_sources.selectedIndex = 1;
-    } else {
-        tmp = [];
-        for (i = 1; i < document.prefs.selected_search_sources.length; i++) {
-            tmp[i - 1] = new Option(document.prefs.selected_search_sources[i].text, document.prefs.selected_search_sources[i].value)
-        }
-
-        for (i = 0; i < tmp.length; i++) {
-            if (i + 1 == sel) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i + 1];
-            } else if (i + 1 == sel + 1) {
-                document.prefs.selected_search_sources[i + 1] = tmp[i - 1];
-            } else {
-                document.prefs.selected_search_sources[i + 1] = tmp[i];
-            }
-        }
-
-        document.prefs.selected_search_sources.selectedIndex = sel + 1;
-    }
-
-    resetHidden();
-}
-
-<?php echo $js ?>
-
-var selectedIndex = false;
-var selectedValue = false;
-var nbSources = <?php echo $nbReadSources ?>;
-<?php if ($nbReadSources == 1): ?>
-selectedIndex = 1;
-selectedValue = "<?php echo $selected[0] ?>";
-<?php endif; ?>
-
-function updateSearchFields()
-{
-    var f = document.prefs;
-    <?php if ($nbReadSources > 1): ?>
-    selectedIndex = f.selected_search_sources.selectedIndex;
-    <?php endif; ?>
-    var fieldString = '';
-
-    while (f.search_fields.length > 0) {
-        f.search_fields.options[f.search_fields.length-1] = null;
-    }
-
-    if (selectedIndex < 1) {
-        return;
-    }
-
-    <?php if ($nbReadSources > 1): ?>
-    selectedValue = f.selected_search_sources.options[selectedIndex].value;
-    <?php endif; ?>
-
-    for (var i = 0; i < searchFields.length; i++) {
-        if (i > 0) {
-            fieldString += "\n";
-        }
-        fieldString += searchFields[i][0];
-        for (var j = 1; j < searchFields[i].length; j++) {
-            if (searchFields[i][j][2]) {
-                fieldString += "\t" + searchFields[i][j][0];
-            }
-
-            if (searchFields[i][0] == selectedValue) {
-                f.search_fields.options[f.search_fields.length] = new Option(searchFields[i][j][1], searchFields[i][j][0]);
-                if (searchFields[i][j][2]) {
-                    f.search_fields.options[f.search_fields.length - 1].selected = true;
-                }
-            }
-        }
-    }
-
-    f.search_fields_string.value = fieldString;
-}
-
-function changeSearchFields()
-{
-    var f = document.prefs;
-    <?php if ($nbReadSources > 1): ?>
-    selectedIndex = f.selected_search_sources.selectedIndex;
-    selectedValue = f.selected_search_sources.options[selectedIndex].value;
-    <?php endif; ?>
-
-    for (var i = 0; i < searchFields.length; i++) {
-        if (searchFields[i][0] == selectedValue) {
-            for (var j = 1; j < searchFields[i].length; j++) {
-                searchFields[i][j][2] = f.search_fields.options[j - 1].selected;
-            }
-            updateSearchFields();
-            return;
-        }
-    }
-}
-</script>
-
-<br />
-<input type="hidden" name="search_sources" value="<?php echo implode("\t", $selected) ?>" />
-<?php if ($nbReadSources > 1): ?>
-<?php echo _("Choose the order of address books to search when expanding addresses.") ?><br />
-<table>
- <tr>
-  <td>
-   <label for="unselected_search_sources" class="hidden"><?php echo _("Available Address books:") ?></label>
-   <select id="unselected_search_sources" name="unselected_search_sources" multiple="multiple" size="5" style="width:20em" onchange="deselectHeaders()">
-    <option value=""><?php echo _("Available Address books:") ?></option>
-    <?php echo $readSelect ?>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="addSource(); return false;"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'lhand.png' : 'rhand.png', _("Add source")) ?></a>
-   <br />
-   <a href="#" onclick="removeSource(); return false;"><?php echo Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'rhand.png' : 'lhand.png', _("Remove source")) ?></a>
-  </td>
-  <td>
-   <label for="selected_search_sources" class="hidden"><?php echo _("Selected Address books:") ?></label>
-   <select name="selected_search_sources" multiple="multiple" size="5" style="width:20em" onchange="deselectHeaders();updateSearchFields();">
-    <option value=""><?php echo _("Selected Address books:") ?></option>
-    <?php echo $prefSelect ?>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="moveSourceUp(); return false;"><?php echo Horde::img('nav/up.png', _("Move up")) ?></a>
-   <br />
-   <a href="#" onclick="moveSourceDown(); return false;"><?php echo Horde::img('nav/down.png', _("Move down")) ?></a>
-  </td>
- </tr>
-</table>
-
-<?php echo _("Click on one of your selected address books and then select all fields to search.") ?><br />
-<?php else: ?>
-<?php echo _("Select all fields to search when expanding addresses.") ?><br />
-<?php endif; ?>
-
-<?php echo _("To select multiple fields, hold down the Control (PC) or Command (Mac) while clicking.") ?><br />
-<input type="hidden" name="search_fields_string" />
-<table>
- <tr>
-  <td>
-   <label for="search_fields" class="hidden"><?php echo _("Fields to search") ?></label>
-   <select id="search_fields" name="search_fields" multiple="multiple" size="5" style="width:20em" onchange="changeSearchFields()">
-    <option><?php echo str_repeat('&nbsp;', 50) ?></option>
-   </select>
-  </td>
- </tr>
-</table>
-
-<script type="text/javascript">
-updateSearchFields();
-</script>
-<?php endif; ?>