[Svn] r4102 - in trunk/roundcubemail: . program/include

trac at roundcube.net trac at roundcube.net
Mon Oct 18 14:55:07 CEST 2010


Author: alec
Date: 2010-10-18 07:55:07 -0500 (Mon, 18 Oct 2010)
New Revision: 4102

Modified:
   trunk/roundcubemail/CHANGELOG
   trunk/roundcubemail/program/include/rcube_imap.php
   trunk/roundcubemail/program/include/rcube_imap_generic.php
Log:
- Add ACL extension support into IMAP classes (RFC4314)                                                                                          
- Add ANNOTATEMORE extension support into IMAP classes (draft-daboo-imap-annotatemore)                                                           
- Add METADATA extension support into IMAP classes (RFC5464)


Modified: trunk/roundcubemail/CHANGELOG
===================================================================
--- trunk/roundcubemail/CHANGELOG	2010-10-17 17:43:05 UTC (rev 4101)
+++ trunk/roundcubemail/CHANGELOG	2010-10-18 12:55:07 UTC (rev 4102)
@@ -32,6 +32,9 @@
 - Display IMAP errors for LIST/THREAD/SEARCH commands (#1486905)
 - Add LITERAL+ (IMAP4 non-synchronizing literals) support (RFC2088)
 - Add separate column for message status icon (#1486665)
+- Add ACL extension support into IMAP classes (RFC4314)
+- Add ANNOTATEMORE extension support into IMAP classes (draft-daboo-imap-annotatemore)
+- Add METADATA extension support into IMAP classes (RFC5464)
 
 RELEASE 0.4.2
 -------------

Modified: trunk/roundcubemail/program/include/rcube_imap.php
===================================================================
--- trunk/roundcubemail/program/include/rcube_imap.php	2010-10-17 17:43:05 UTC (rev 4101)
+++ trunk/roundcubemail/program/include/rcube_imap.php	2010-10-18 12:55:07 UTC (rev 4102)
@@ -3125,6 +3125,251 @@
     }
 
 
+    /* -----------------------------------------
+     *   ACL and METADATA/ANNOTATEMORE methods
+     * ----------------------------------------*/
+
+    /**
+     * Changes the ACL on the specified mailbox (SETACL)
+     *
+     * @param string $mailbox Mailbox name
+     * @param string $user    User name
+     * @param string $acl     ACL string
+     *
+     * @return boolean True on success, False on failure
+     *
+     * @access public
+     * @since 0.5-beta
+     */
+    function set_acl($mailbox, $user, $acl)
+    {
+        $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('ACL'))
+            return $this->conn->setACL($mailbox, $user, $acl);
+
+        return false;
+    }
+
+
+    /**
+     * Removes any <identifier,rights> pair for the
+     * specified user from the ACL for the specified
+     * mailbox (DELETEACL)
+     *
+     * @param string $mailbox Mailbox name
+     * @param string $user    User name
+     *
+     * @return boolean True on success, False on failure
+     *
+     * @access public
+     * @since 0.5-beta
+     */
+    function delete_acl($mailbox, $user)
+    {
+        $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('ACL'))
+            return $this->conn->deleteACL($mailbox, $user);
+
+        return false;
+    }
+
+
+    /**
+     * Returns the access control list for mailbox (GETACL)
+     *
+     * @param string $mailbox Mailbox name
+     *
+     * @return array User-rights array on success, NULL on error
+     * @access public
+     * @since 0.5-beta
+     */
+    function get_acl($mailbox)
+    {
+        $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('ACL'))
+            return $this->conn->getACL($mailbox);
+
+        return NULL;
+    }
+
+
+    /**
+     * Returns information about what rights can be granted to the
+     * user (identifier) in the ACL for the mailbox (LISTRIGHTS)
+     *
+     * @param string $mailbox Mailbox name
+     * @param string $user    User name
+     *
+     * @return array List of user rights
+     * @access public
+     * @since 0.5-beta
+     */
+    function list_rights($mailbox, $user)
+    {
+        $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('ACL'))
+            return $this->conn->listRights($mailbox, $user);
+
+        return NULL;
+    }
+
+
+    /**
+     * Returns the set of rights that the current user has to
+     * mailbox (MYRIGHTS)
+     *
+     * @param string $mailbox Mailbox name
+     *
+     * @return array MYRIGHTS response on success, NULL on error
+     * @access public
+     * @since 0.5-beta
+     */
+    function my_rights($mailbox)
+    {
+        $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('ACL'))
+            return $this->conn->myRights($mailbox);
+
+        return NULL;
+    }
+
+
+    /**
+     * Sets IMAP metadata/annotations (SETMETADATA/SETANNOTATION)
+     *
+     * @param string $mailbox Mailbox name (empty for server metadata)
+     * @param array  $entries Entry-value array (use NULL value as NIL)
+     *
+     * @return boolean True on success, False on failure
+     * @access public
+     * @since 0.5-beta
+     */
+    function set_metadata($mailbox, $entries)
+    {
+        if ($mailbox)
+            $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('METADATA') || 
+            empty($mailbox) && $this->get_capability('METADATA-SERVER')
+        ) {
+            return $this->conn->setMetadata($mailbox, $entries);
+        }
+        else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) {
+            foreach ($entries as $entry => $value) {
+                list($ent, $attr) = $this->md2annotate($entry);
+                $entries[$entry] = array($ent, $attr, $value);
+            }
+            return $this->conn->setAnnotation($mailbox, $entries);
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Unsets IMAP metadata/annotations (SETMETADATA/SETANNOTATION)
+     *
+     * @param string $mailbox Mailbox name (empty for server metadata)
+     * @param array  $entries Entry names array
+     *
+     * @return boolean True on success, False on failure
+     *
+     * @access public
+     * @since 0.5-beta
+     */
+    function delete_metadata($mailbox, $entries)
+    {
+        if ($mailbox)
+            $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('METADATA') || 
+            empty($mailbox) && $this->get_capability('METADATA-SERVER')
+        ) {
+            return $this->conn->deleteMetadata($mailbox, $entries);
+        }
+        else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) {
+            foreach ($entries as $idx => $entry) {
+                list($ent, $attr) = $this->md2annotate($entry);
+                $entries[$idx] = array($ent, $attr, NULL);
+            }
+            return $this->conn->setAnnotation($mailbox, $entries);
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION)
+     *
+     * @param string $mailbox Mailbox name (empty for server metadata)
+     * @param array  $entries Entries
+     * @param array  $options Command options (with MAXSIZE and DEPTH keys)
+     *
+     * @return array Metadata entry-value hash array on success, NULL on error
+     *
+     * @access public
+     * @since 0.5-beta
+     */
+    function get_metadata($mailbox, $entries, $options=array())
+    {
+        if ($mailbox)
+            $mailbox = $this->mod_mailbox($mailbox);
+
+        if ($this->get_capability('METADATA') || 
+            empty($mailbox) && $this->get_capability('METADATA-SERVER')
+        ) {
+            return $this->conn->getMetadata($mailbox, $entries, $options);
+        }
+        else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) {
+            $queries = array();
+            $res     = array();
+
+            // Convert entry names
+            foreach ($entries as $entry) {
+                list($ent, $attr) = $this->md2annotate($entry);
+                $queries[$attr][] = $ent;
+            }
+
+            // @TODO: Honor MAXSIZE and DEPTH options
+            foreach ($queries as $attrib => $entry)
+                if ($result = $this->conn->getAnnotation($mailbox, $entry, $attrib))
+                    $res = array_merge($res, $result);
+
+            return $res;
+        }
+
+        return NULL;
+    }
+
+
+    /**
+     * Converts the METADATA extension entry name into the correct
+     * entry-attrib names for older ANNOTATEMORE version.
+     *
+     * @param string Entry name
+     *
+     * @return array Entry-attribute list, NULL if not supported (?)
+     */
+    private function md2annotate($name)
+    {
+        if (substr($entry, 0, 7) == '/shared') {
+            return array(substr($entry, 7), 'value.shared');
+        }
+        else if (substr($entry, 0, 8) == '/private') {
+            return array(substr($entry, 8), 'value.priv');
+        }
+
+        // @TODO: log error
+        return NULL;
+    }
+
+
     /* --------------------------------
      *   internal caching methods
      * --------------------------------*/

Modified: trunk/roundcubemail/program/include/rcube_imap_generic.php
===================================================================
--- trunk/roundcubemail/program/include/rcube_imap_generic.php	2010-10-17 17:43:05 UTC (rev 4101)
+++ trunk/roundcubemail/program/include/rcube_imap_generic.php	2010-10-18 12:55:07 UTC (rev 4102)
@@ -2181,6 +2181,607 @@
 	    return $result;
     }
 
+    /**
+     * Send the SETACL command (RFC4314)
+     *
+     * @param string $mailbox Mailbox name
+     * @param string $user    User name
+     * @param mixed  $acl     ACL string or array
+     *
+     * @return boolean True on success, False on failure
+     *
+     * @access public
+     * @since 0.5-beta
+     */
+    function setACL($mailbox, $user, $acl)
+    {
+        if (is_array($acl)) {
+            $acl = implode('', $acl);
+        }
+
+        $key     = 'acl1';
+        $command = sprintf("%s SETACL \"%s\" \"%s\" %s",
+            $key, $this->escape($mailbox), $this->escape($user), strtolower($acl));
+
+		if (!$this->putLine($command)) {
+            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");        
+            return false;
+        }
+
+		$line = $this->readReply();
+	    return ($this->parseResult($line, 'SETACL: ') == self::ERROR_OK);
+    }
+
+    /**
+     * Send the DELETEACL command (RFC4314)
+     *
+     * @param string $mailbox Mailbox name
+     * @param string $user    User name
+     *
+     * @return boolean True on success, False on failure
+     *
+     * @access public
+     * @since 0.5-beta
+     */
+    function deleteACL($mailbox, $user)
+    {
+        $key     = 'acl2';
+        $command = sprintf("%s DELETEACL \"%s\" \"%s\"", 
+            $key, $this->escape($mailbox), $this->escape($user));
+
+		if (!$this->putLine($command)) {
+            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");        
+            return false;
+        }
+
+		$line = $this->readReply();
+	    return ($this->parseResult($line, 'DELETEACL: ') == self::ERROR_OK);
+    }
+
+    /**
+     * Send the GETACL command (RFC4314)
+     *
+     * @param string $mailbox Mailbox name
+     *
+     * @return array User-rights array on success, NULL on error
+     * @access public
+     * @since 0.5-beta
+     */
+    function getACL($mailbox)
+    {
+        $key     = 'acl3';
+        $command = sprintf("%s GETACL \"%s\"", $key, $this->escape($mailbox));
+
+		if (!$this->putLine($command)) {
+            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
+            return NULL;
+        }
+
+        $response = '';
+
+		do {
+		    $line = $this->readLine(4096);
+            $response .= $line;
+        } while (!$this->startsWith($line, $key, true, true));
+        
+        if ($this->parseResult($line, 'GETACL: ') == self::ERROR_OK) {
+            // Parse server response (remove "* ACL " and "\r\nacl3 OK...")
+            $response = substr($response, 6, -(strlen($line)+2));
+            $ret  = $this->tokenizeResponse($response);
+            $mbox = array_unshift($ret);
+            $size = count($ret);
+
+            // Create user-rights hash array
+            // @TODO: consider implementing fixACL() method according to RFC4314.2.1.1
+            // so we could return only standard rights defined in RFC4314,
+            // excluding 'c' and 'd' defined in RFC2086.
+            if ($size % 2 == 0) {
+                for ($i=0; $i<$size; $i++) {
+                    $ret[$ret[$i]] = str_split($ret[++$i]);
+                    unset($ret[$i-1]);
+                    unset($ret[$i]);
+                }
+                return $ret;
+            }
+
+            $this->set_error(self::ERROR_COMMAND, "Incomplete ACL response");
+            return NULL;
+        }
+
+        return NULL;
+    }
+
+    /**
+     * Send the LISTRIGHTS command (RFC4314)
+     *
+     * @param string $mailbox Mailbox name
+     * @param string $user    User name
+     *
+     * @return array List of user rights
+     * @access public
+     * @since 0.5-beta
+     */
+    function listRights($mailbox, $user)
+    {
+        $key     = 'acl4';
+        $command = sprintf("%s LISTRIGHTS \"%s\" \"%s\"",
+            $key, $this->escape($mailbox), $this->escape($user));
+
+		if (!$this->putLine($command)) {
+            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");        
+            return NULL;
+        }
+
+        $response = '';
+
+		do {
+		    $line = $this->readLine(4096);
+            $response .= $line;
+        } while (!$this->startsWith($line, $key, true, true));
+
+        if ($this->parseResult($line, 'LISTRIGHTS: ') == self::ERROR_OK) {
+            // Parse server response (remove "* LISTRIGHTS " and "\r\nacl3 OK...")
+            $response = substr($response, 13, -(strlen($line)+2));
+
+            $ret_mbox = $this->tokenizeResponse($response, 1);
+            $ret_user = $this->tokenizeResponse($response, 1);
+            $granted  = $this->tokenizeResponse($response, 1);
+            $optional = trim($response);
+
+            return array(
+                'granted'  => str_split($granted),
+                'optional' => explode(' ', $optional),
+            );
+        }
+
+        return NULL;
+    }
+
+    /**
+     * Send the MYRIGHTS command (RFC4314)
+     *
+     * @param string $mailbox Mailbox name
+     *
+     * @return array MYRIGHTS response on success, NULL on error
+     * @access public
+     * @since 0.5-beta
+     */
+    function myRights($mailbox)
+    {
+