Move ACL code into IMP.
authorMichael M Slusarz <slusarz@curecanti.org>
Wed, 10 Dec 2008 08:48:35 +0000 (01:48 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 10 Dec 2008 08:52:34 +0000 (01:52 -0700)
Lots of cleanup - move all code into one file - use Horde_Imap_Client
object to interact with the IMAP server.
First attempt and guaranteed this doesn't work (I don't have a way to
test right now) but at least all the parts are there for future
development.

imp/acl.php
imp/lib/IMAP/ACL.php [new file with mode: 0644]

index e16030c..edb805c 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 /**
+ * ACL (Access Control List) administration page.
+ *
  * Copyright 2000-2008 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * @author Eric Garrido <ekg2002@columbia.edu>
  */
 
-@define('IMP_BASE', dirname(__FILE__));
-require_once IMP_BASE . '/lib/base.php';
-require_once 'Horde/IMAP/ACL.php';
-
-$prefs_url = IMP::prefsURL(true);
+require_once dirname(__FILE__) . '/lib/base.php';
 
 /* Redirect back to the options screen if ACL is not enabled. */
-if ($prefs->isLocked('acl') ||
-    !(isset($_SESSION['imp']['acl']) && is_array($_SESSION['imp']['acl']))) {
+$prefs_url = IMP::prefsURL(true);
+if ($prefs->isLocked('acl') || empty($_SESSION['imp']['acl'])) {
     $notification->push(_("Folder sharing is not enabled."), 'horde.error');
     header('Location: ' . $prefs_url);
     exit;
 }
 
-$params = array(
-    'hostspec' => $_SESSION['imp']['server'],
-    'password' => Secret::read(IMP::getAuthKey(), $_SESSION['imp']['pass']),
-    'port' => $_SESSION['imp']['port'],
-    'protocol' => $_SESSION['imp']['protocol'],
-    'username' => $_SESSION['imp']['user'],
-);
-
-if (isset($_SESSION['imp']['acl']['params'])) {
-    $params = array_merge($params, $_SESSION['imp']['acl']['params']);
-}
-
-$ACLDriver = &IMAP_ACL::singleton($_SESSION['imp']['acl']['driver'], $params);
-
-/* Check selected driver is supported. Redirect to options screen with
- * error message if not. */
-$error = (!$ACLDriver->isSupported())
-    ? _("This server does not support sharing folders.")
-    : $ACLDriver->getError();
-
-if ($error) {
-    $notification->push($error, 'horde.error');
+try {
+    $ACLDriver = &IMP_IMAP_ACL::singleton();
+} catch (Exception $e) {
+    $notification->push($error, _("This server does not support sharing folders."));
     header('Location: ' . $prefs_url);
     exit;
 }
@@ -64,9 +44,8 @@ if ($new_user) {
 $protected = $ACLDriver->getProtected();
 
 /* Run through the action handlers. */
-$actionID = Util::getFormData('actionID');
 $ok_form = true;
-switch ($actionID) {
+switch (Util::getFormData('actionID')) {
 case 'imp_acl_set':
     if (!$folder) {
         $notification->push(_("No folder selected."), 'horde.error');
@@ -75,9 +54,9 @@ case 'imp_acl_set':
 
     if ($new_user) {
         /* Each ACL is submitted with the acl as the value. Reverse the hash
-           mapping for createACL(). */
+           mapping for editACL(). */
         $new_acl = array_flip($new_acl);
-        $result = $ACLDriver->createACL($folder, $new_user, $new_acl);
+        $result = $ACLDriver->editACL($folder, $new_user, $new_acl);
         if (is_a($result, 'PEAR_Error')) {
             $notification->push($result);
         } elseif (!count($new_acl)) {
@@ -133,19 +112,13 @@ case 'imp_acl_set':
 
 $imp_folder = &IMP_Folder::singleton();
 $rights = $ACLDriver->getRights();
-$rightsTitles = $ACLDriver->getRightsTitles();
 
 if (empty($folder)) {
     $folder = 'INBOX';
 }
 
 $curr_acl = $ACLDriver->getACL($folder);
-$canEdit = $ACLDriver->canEdit($folder, $_SESSION['imp']['user']);
-
-if (is_a($curr_acl, 'PEAR_Error')) {
-    $notification->push($curr_acl, 'horde_error');
-    $curr_acl = array();
-}
+$canEdit = $ACLDriver->canEdit($folder, $_SESSION['imp']['uniquser']);
 
 require_once 'Horde/Prefs/UI.php';
 $result = Horde::loadConfiguration('prefs.php', array('prefGroups', '_prefs'), 'imp');
@@ -165,7 +138,7 @@ $t->set('forminput', Util::formInput());
 $t->set('aclnavcell', Util::bufferOutput(array('Prefs_UI', 'generateNavigationCell'), 'acl'));
 $t->set('changefolder', Horde::link('#', _("Change Folder"), 'smallheader', '', 'ACLFolderChange(true); return false;'));
 $t->set('sharedimg', Horde::img('shared.png', _("Change Folder")));
-$t->set('options', IMP::flistSelect(array('selected' => $folder));
+$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));
@@ -183,7 +156,7 @@ if (!$t->get('noacl')) {
         /* 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'=> isset($rule{$val}));
+            $entry['rule'][] = array('val' => $val, 'enabled' => isset($rule[$val]));
         }
         $cval[] = $entry;
     }
@@ -209,13 +182,15 @@ if (empty($_SESSION['imp']['admin'])) {
     $new_user_field .= "\n</select>";
 }
 $t->set('new_user', $new_user_field);
+
 $rightsTitlesval = array();
-foreach ($rightsTitles as $right => $desc) {
+foreach ($rights as $right => $val) {
     $rightsval[] = array(
         'right' => $right,
-        'desc' => $desc
+        'desc' => $val['desc']
     );
 }
+
 $t->set('rights', $rightsval);
 $t->set('width', round(100 / (count($rightsval) + 1)) . '%');
 $t->set('prefsurl', $prefs_url);
diff --git a/imp/lib/IMAP/ACL.php b/imp/lib/IMAP/ACL.php
new file mode 100644 (file)
index 0000000..6ed8436
--- /dev/null
@@ -0,0 +1,211 @@
+<?php
+/**
+ * Contains functions related to managing IMAP Access Control Lists.
+ *
+ * Copyright 2003-2008 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  Chris Hastie <imp@oak-wood.co.uk>
+ * @package IMP
+ */
+class IMP_IMAP_ACL
+{
+    /**
+     * Hash containing the list of possible rights and a human readable
+     * description of each.
+     *
+     * @var array
+     */
+    protected $_rightsList;
+
+    /**
+     * Array containing user names that cannot have their access rights
+     * changed.
+     *
+     * @var boolean
+     */
+    protected $_protected;
+
+    /**
+     * Attempts to return a reference to a concrete object instance.
+     * It will only create a new instance if no instance currently exists.
+     *
+     * This method must be invoked as:
+     *   $var = &IMP_IMAP_ACL::singleton()
+     *
+     * @return IMP_IMAP_ACL  The created concrete instance.
+     */
+    static public function &singleton($driver, $params = array())
+    {
+        static $instance;
+
+        if (!isset($instance)) {
+            $instances = new IMP_IMAP_ACL();
+        }
+
+        return $instances[$signature];
+    }
+
+    /**
+     * Constructor.
+     */
+    function __construct()
+    {
+        if ($_SESSION['imp']['protocol'] != 'imap') {
+            throw new Exception(_("ACL requires an IMAP server."));
+        }
+
+        $capability = $GLOBALS['imp_imap']->ob->queryCapability('ACL');
+        if (!$capability) {
+            throw new Exception(_("IMAP server does not support ACLs."));
+        }
+
+        $rfc4314 = $GLOBALS['imp_imap']->ob->queryCapability('RIGHTS');
+
+        $this->_protected = array($GLOBALS['imp_imap']->ob->getParam('username'));
+
+        $this->_rightsList = array(
+            'l' => array(
+                'desc' => _("List - user can see the folder"),
+                'title' => _("List")
+            ),
+            'r' => array(
+                'desc' => _("Read messages"),
+                'title' => _("Read")
+            ),
+            's' => array(
+                'desc' => _("Mark with Seen/Unseen flags"),
+                'title' => _("Mark (Seen)")
+            ),
+            'w' => array(
+                'desc' => _("Mark with other flags (e.g. Important/Answered)"),
+                'title' => _("Mark (Other)")
+            ),
+            'i' => array(
+                'desc' => _("Insert messages"),
+                'title' => _("Insert")
+            ),
+            'p' => array(
+                'desc' => _("Post to this folder (not enforced by IMAP)"),
+                'title' => _("Post")
+            ),
+            'a' => array(
+                'desc' => _("Administer - set permissions for other users"),
+                'title' => _("Administer")
+            )
+        );
+
+        if ($rfc4314) {
+            // RFC 4314 compliant rights
+            $this->_rightsList = array_merge($this->_rightsList, array(
+                'k' => array(
+                    'desc' => _("Create sub folders"),
+                    'title' => _("Create Folders")
+                ),
+                'x' => array(
+                    'desc' => _("Delete sub folders"),
+                    'title' => _("Delete Folders")
+                ),
+                't' => array(
+                    'desc' => _("Delete messages"),
+                    'title' => _("Delete")
+                ),
+                'e' => array(
+                    'desc' => _("Purge messages"),
+                    'title' => _("Purge")
+                )
+            ));
+        } else {
+            // RFC 2086 compliant rights
+            $this->_rightsList = array_merge($this->_rightsList, array(
+                'c' => array(
+                    'desc' =>_("Create sub folders"),
+                    'title' => _("Create Folder")
+                ),
+                'd' => array(
+                    'desc' => _("Delete and purge messages"),
+                    'title' => _("Delete/Purge")
+                )
+            ));
+        }
+    }
+
+    /**
+     * Attempts to retrieve the existing ACL for a mailbox from the server.
+     *
+     * @param string $mbox  The mailbox to get the ACL for.
+     *
+     * @return array  A hash containing information on the ACL.
+     */
+    public function getACL($mbox)
+    {
+        try {
+            return $GLOBALS['imp_imap']->ob->getACL($mbox);
+        } catch (Horde_Imap_Client_Exception $e) {
+            // return PEAR::raiseError(_("Could not retrieve ACL"));
+            return array();
+        }
+    }
+
+    /**
+     * Edits an ACL on the server.
+     *
+     * @param string $mbox  The mailbox on which to edit the ACL.
+     * @param string $user  The user to grant rights to.
+     * @param array $acl    The keys of which are the
+     *                      rights to be granted (see RFC 2086).
+     *
+     * @return mixed  True on success, PEAR_Error on error.
+     */
+    public function editACL($mbox, $user, $acl)
+    {
+        try {
+            $GLOBALS['imp_imap']->ob->setACL($mbox, $user, array('rights' => $acl));
+            return true;
+        } catch (Horde_Imap_Client_Exception $e) {
+            return PEAR::raiseError(sprintf(_("Couldn't give user \"%s\" the following rights for the folder \"%s\": %s"), $user, $mbox, implode('', $acl)));
+        }
+    }
+
+    /**
+     * Can a user edit the ACL for this mailbox?
+     *
+     * @param string $mbox  The mailbox name.
+     * @param string $user  A user name.
+     *
+     * @return boolean  True if $user has 'a' right
+     */
+    public function canEdit($mbox, $user)
+    {
+        try {
+            $rights = $GLOBALS['imp_imap']->ob->listACLRights($mbox, $user);
+            foreach ($rights as $val) {
+                if (strpos($val, 'a') !== false) {
+                    return true;
+                }
+            }
+            return false;
+        } catch (Horde_Imap_Client_Exception $e) {
+            return false;
+        }
+    }
+
+    /**
+     * TODO
+     */
+    public function getRights()
+    {
+        return $this->_rightsList;
+    }
+
+    /**
+     * TODO
+     */
+    public function getProtected()
+    {
+        return $this->_protected;
+    }
+
+}