Changeset 3085 in subversion


Ignore:
Timestamp:
Nov 2, 2009 2:41:21 AM (4 years ago)
Author:
alec
Message:
  • Managesieve 2.0: multi-script support
Location:
trunk/roundcubemail
Files:
3 added
13 deleted
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/roundcubemail/CHANGELOG

    r3084 r3085  
    22=========================== 
    33 
     4- Managesieve 2.0: multi-script support 
    45- Fix imap_auth_type regression (#1486263) 
    56 
  • trunk/roundcubemail/plugins/managesieve/Changelog

    r2970 r3085  
     1* version 2.0 [2009-11-02] 
     2----------------------------------------------------------- 
     3- Added 'managesieve_debug' option 
     4- Added multi-script support 
     5- Small css improvements + sprite image buttons 
     6- PEAR::NetSieve 1.2.0b1 
     7 
    18* version 1.7 [2009-09-20] 
    29----------------------------------------------------------- 
  • trunk/roundcubemail/plugins/managesieve/config.inc.php.dist

    r2963 r3085  
    3232$rcmail_config['managesieve_disabled_extensions'] = array(); 
    3333 
     34// Enables debugging of conversation with sieve server. Logs it into <log_dir>/sieve 
     35$rcmail_config['managesieve_debug'] = false; 
     36 
    3437?> 
  • trunk/roundcubemail/plugins/managesieve/lib/Net/Sieve.php

    r2807 r3085  
    11<?php 
    2 // +-----------------------------------------------------------------------+ 
    3 // | Copyright (c) 2002-2003, Richard Heyes                                | 
    4 // | Copyright (c) 2006,2008 Anish Mistry                                  | 
    5 // | All rights reserved.                                                  | 
    6 // |                                                                       | 
    7 // | Redistribution and use in source and binary forms, with or without    | 
    8 // | modification, are permitted provided that the following conditions    | 
    9 // | are met:                                                              | 
    10 // |                                                                       | 
    11 // | o Redistributions of source code must retain the above copyright      | 
    12 // |   notice, this list of conditions and the following disclaimer.       | 
    13 // | o Redistributions in binary form must reproduce the above copyright   | 
    14 // |   notice, this list of conditions and the following disclaimer in the | 
    15 // |   documentation and/or other materials provided with the distribution.| 
    16 // | o The names of the authors may not be used to endorse or promote      | 
    17 // |   products derived from this software without specific prior written  | 
    18 // |   permission.                                                         | 
    19 // |                                                                       | 
    20 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   | 
    21 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     | 
    22 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
    23 // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  | 
    24 // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
    25 // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      | 
    26 // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
    27 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
    28 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   | 
    29 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
    30 // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
    31 // |                                                                       | 
    32 // +-----------------------------------------------------------------------+ 
    33 // | Author: Richard Heyes <richard@phpguru.org>                           | 
    34 // | Co-Author: Damian Fernandez Sosa <damlists@cnba.uba.ar>               | 
    35 // | Co-Author: Anish Mistry <amistry@am-productions.biz>                  | 
    36 // +-----------------------------------------------------------------------+ 
    37  
    38 require_once('Net/Socket.php'); 
    39  
    402/** 
    41 * TODO 
    42 * 
    43 * o supportsAuthMech() 
    44 */ 
     3 * This file contains the Net_Sieve class. 
     4 * 
     5 * PHP version 4 
     6 * 
     7 * +-----------------------------------------------------------------------+ 
     8 * | All rights reserved.                                                  | 
     9 * |                                                                       | 
     10 * | Redistribution and use in source and binary forms, with or without    | 
     11 * | modification, are permitted provided that the following conditions    | 
     12 * | are met:                                                              | 
     13 * |                                                                       | 
     14 * | o Redistributions of source code must retain the above copyright      | 
     15 * |   notice, this list of conditions and the following disclaimer.       | 
     16 * | o Redistributions in binary form must reproduce the above copyright   | 
     17 * |   notice, this list of conditions and the following disclaimer in the | 
     18 * |   documentation and/or other materials provided with the distribution.| 
     19 * |                                                                       | 
     20 * | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   | 
     21 * | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     | 
     22 * | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
     23 * | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  | 
     24 * | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
     25 * | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      | 
     26 * | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
     27 * | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
     28 * | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   | 
     29 * | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
     30 * | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
     31 * +-----------------------------------------------------------------------+ 
     32 * 
     33 * @category  Networking 
     34 * @package   Net_Sieve 
     35 * @author    Richard Heyes <richard@phpguru.org> 
     36 * @author    Damian Fernandez Sosa <damlists@cnba.uba.ar> 
     37 * @author    Anish Mistry <amistry@am-productions.biz> 
     38 * @author    Jan Schneider <jan@horde.org> 
     39 * @copyright 2002-2003 Richard Heyes 
     40 * @copyright 2006-2008 Anish Mistry 
     41 * @license   http://www.opensource.org/licenses/bsd-license.php BSD 
     42 * @version   SVN: $Id: Sieve.php 289313 2009-10-07 22:26:33Z yunosh $ 
     43 * @link      http://pear.php.net/package/Net_Sieve 
     44 */ 
     45 
     46require_once 'PEAR.php'; 
     47require_once 'Net/Socket.php'; 
    4548 
    4649/** 
    47 * Disconnected state 
    48 * @const NET_SIEVE_STATE_DISCONNECTED 
    49 */ 
    50 define('NET_SIEVE_STATE_DISCONNECTED',  1, true); 
     50 * TODO 
     51 * 
     52 * o supportsAuthMech() 
     53 */ 
    5154 
    5255/** 
    53 * Authorisation state 
    54 * @const NET_SIEVE_STATE_AUTHORISATION 
    55 */ 
     56 * Disconnected state 
     57 * @const NET_SIEVE_STATE_DISCONNECTED 
     58 */ 
     59define('NET_SIEVE_STATE_DISCONNECTED', 1, true); 
     60 
     61/** 
     62 * Authorisation state 
     63 * @const NET_SIEVE_STATE_AUTHORISATION 
     64 */ 
    5665define('NET_SIEVE_STATE_AUTHORISATION', 2, true); 
    5766 
    5867/** 
    59 * Transaction state 
    60 * @const NET_SIEVE_STATE_TRANSACTION 
    61 */ 
    62 define('NET_SIEVE_STATE_TRANSACTION',   3, true); 
     68 * Transaction state 
     69 * @const NET_SIEVE_STATE_TRANSACTION 
     70 */ 
     71define('NET_SIEVE_STATE_TRANSACTION', 3, true); 
     72 
    6373 
    6474/** 
    65 * A class for talking to the timsieved server which 
    66 * comes with Cyrus IMAP. 
    67 * 
    68 * SIEVE: RFC3028 http://www.ietf.org/rfc/rfc3028.txt 
    69 * MANAGE-SIEVE: http://www.ietf.org/internet-drafts/draft-martin-managesieve-07.txt 
    70 * 
    71 * @author  Richard Heyes <richard@php.net> 
    72 * @author  Damian Fernandez Sosa <damlists@cnba.uba.ar> 
    73 * @author  Anish Mistry <amistry@am-productions.biz> 
    74 * @access  public 
    75 * @version 1.2.0 
    76 * @package Net_Sieve 
    77 */ 
    78  
     75 * A class for talking to the timsieved server which comes with Cyrus IMAP. 
     76 * 
     77 * @category  Networking 
     78 * @package   Net_Sieve 
     79 * @author    Richard Heyes <richard@phpguru.org> 
     80 * @author    Damian Fernandez Sosa <damlists@cnba.uba.ar> 
     81 * @author    Anish Mistry <amistry@am-productions.biz> 
     82 * @author    Jan Schneider <jan@horde.org> 
     83 * @copyright 2002-2003 Richard Heyes 
     84 * @copyright 2006-2008 Anish Mistry 
     85 * @license   http://www.opensource.org/licenses/bsd-license.php BSD 
     86 * @version   Release: @package_version@ 
     87 * @link      http://pear.php.net/package/Net_Sieve 
     88 * @link      http://www.ietf.org/rfc/rfc3028.txt RFC 3028 (Sieve: A Mail 
     89 *            Filtering Language) 
     90 * @link      http://tools.ietf.org/html/draft-ietf-sieve-managesieve A 
     91 *            Protocol for Remotely Managing Sieve Scripts 
     92 */ 
    7993class Net_Sieve 
    8094{ 
    8195    /** 
    82     * The socket object 
    83     * @var object 
    84     */ 
     96     * The authentication methods this class supports. 
     97     * 
     98     * Can be overwritten if having problems with certain methods. 
     99     * 
     100     * @var array 
     101     */ 
     102    var $supportedAuthMethods = array('DIGEST-MD5', 'CRAM-MD5', 'EXTERNAL', 
     103                                      'PLAIN' , 'LOGIN'); 
     104 
     105    /** 
     106     * SASL authentication methods that require Auth_SASL. 
     107     * 
     108     * @var array 
     109     */ 
     110    var $_supportedSASLAuthMethods = array('DIGEST-MD5', 'CRAM-MD5'); 
     111 
     112    /** 
     113     * The socket handle. 
     114     * 
     115     * @var resource 
     116     */ 
    85117    var $_sock; 
    86118 
    87119    /** 
    88     * Info about the connect 
    89     * @var array 
    90     */ 
     120     * Parameters and connection information. 
     121     * 
     122     * @var array 
     123     */ 
    91124    var $_data; 
    92125 
    93126    /** 
    94     * Current state of the connection 
    95     * @var integer 
    96     */ 
     127     * Current state of the connection. 
     128     * 
     129     * One of the NET_SIEVE_STATE_* constants. 
     130     * 
     131     * @var integer 
     132     */ 
    97133    var $_state; 
    98134 
    99135    /** 
    100     * Constructor error is any 
    101     * @var object 
    102     */ 
     136     * Constructor error. 
     137     * 
     138     * @var PEAR_Error 
     139     */ 
    103140    var $_error; 
    104141 
    105142    /** 
    106     * To allow class debuging 
    107     * @var boolean 
    108     */ 
     143     * Whether to enable debugging. 
     144     * 
     145     * @var boolean 
     146     */ 
    109147    var $_debug = false; 
    110148 
    111149    /** 
    112     * Allows picking up of an already established connection 
    113     * @var boolean 
    114     */ 
     150     * Debug output handler. 
     151     * 
     152     * This has to be a valid callback. 
     153     * 
     154     * @var string|array 
     155     */ 
     156    var $_debug_handler = null; 
     157 
     158    /** 
     159     * Whether to pick up an already established connection. 
     160     * 
     161     * @var boolean 
     162     */ 
    115163    var $_bypassAuth = false; 
    116164 
    117165    /** 
    118     * Whether to use TLS if available 
    119     * @var boolean 
    120     */ 
     166     * Whether to use TLS if available. 
     167     * 
     168     * @var boolean 
     169     */ 
    121170    var $_useTLS = true; 
    122171 
    123172    /** 
    124     * Additional options for stream_context_create() 
    125     * @var array 
    126     */ 
     173     * Additional options for stream_context_create(). 
     174     * 
     175     * @var array 
     176     */ 
    127177    var $_options = null; 
    128178 
    129179    /** 
    130     * The auth methods this class support 
    131     * @var array 
    132     */ 
    133     var $supportedAuthMethods=array('DIGEST-MD5', 'CRAM-MD5', 'EXTERNAL', 'PLAIN' , 'LOGIN'); 
    134     //if you have problems using DIGEST-MD5 authentication  please comment the line above and uncomment the following line 
    135     //var $supportedAuthMethods=array( 'CRAM-MD5', 'PLAIN' , 'LOGIN'); 
    136  
    137     //var $supportedAuthMethods=array( 'PLAIN' , 'LOGIN'); 
    138  
    139     /** 
    140     * The auth methods this class support 
    141     * @var array 
    142     */ 
    143     var $supportedSASLAuthMethods=array('DIGEST-MD5', 'CRAM-MD5'); 
    144  
    145     /** 
    146     * Handles posible referral loops 
    147     * @var array 
    148     */ 
     180     * Maximum number of referral loops 
     181     * 
     182     * @var array 
     183     */ 
    149184    var $_maxReferralCount = 15; 
    150185 
    151186    /** 
    152     * Constructor 
    153     * Sets up the object, connects to the server and logs in. stores 
    154     * any generated error in $this->_error, which can be retrieved 
    155     * using the getError() method. 
    156     * 
    157     * @param  string $user      Login username 
    158     * @param  string $pass      Login password 
    159     * @param  string $host      Hostname of server 
    160     * @param  string $port      Port of server 
    161     * @param  string $logintype Type of login to perform 
    162     * @param  string $euser     Effective User (if $user=admin, login as $euser) 
    163     * @param  string $bypassAuth Skip the authentication phase.  Useful if the socket 
    164                                   is already open. 
    165     * @param  boolean $useTLS Use TLS if available 
    166     * @param  array  $options   options for stream_context_create() 
    167     */ 
    168     function Net_Sieve($user = null , $pass  = null , $host = 'localhost', $port = 2000, $logintype = '', $euser = '', $debug = false, $bypassAuth = false, $useTLS = true, $options = null) 
    169     { 
    170         $this->_state = NET_SIEVE_STATE_DISCONNECTED; 
    171         $this->_data['user'] = $user; 
    172         $this->_data['pass'] = $pass; 
    173         $this->_data['host'] = $host; 
    174         $this->_data['port'] = $port; 
     187     * Constructor. 
     188     * 
     189     * Sets up the object, connects to the server and logs in. Stores any 
     190     * generated error in $this->_error, which can be retrieved using the 
     191     * getError() method. 
     192     * 
     193     * @param string  $user       Login username. 
     194     * @param string  $pass       Login password. 
     195     * @param string  $host       Hostname of server. 
     196     * @param string  $port       Port of server. 
     197     * @param string  $logintype  Type of login to perform (see 
     198     *                            $supportedAuthMethods). 
     199     * @param string  $euser      Effective user. If authenticating as an 
     200     *                            administrator, login as this user. 
     201     * @param boolean $debug      Whether to enable debugging (@see setDebug()). 
     202     * @param string  $bypassAuth Skip the authentication phase. Useful if the 
     203     *                            socket is already open. 
     204     * @param boolean $useTLS     Use TLS if available. 
     205     * @param array   $options    Additional options for 
     206     *                            stream_context_create(). 
     207     */ 
     208    function Net_Sieve($user = null, $pass  = null, $host = 'localhost', 
     209        $port = 2000, $logintype = '', $euser = '', $debug = false, 
     210        $bypassAuth = false, $useTLS = true, $options = null 
     211    ) { 
     212        $this->_state             = NET_SIEVE_STATE_DISCONNECTED; 
     213        $this->_data['user']      = $user; 
     214        $this->_data['pass']      = $pass; 
     215        $this->_data['host']      = $host; 
     216        $this->_data['port']      = $port; 
    175217        $this->_data['logintype'] = $logintype; 
    176         $this->_data['euser'] = $euser; 
    177         $this->_sock = &new Net_Socket(); 
     218        $this->_data['euser']     = $euser; 
     219        $this->_sock              = new Net_Socket(); 
     220        $this->_debug             = $debug; 
     221        $this->_bypassAuth        = $bypassAuth; 
     222        $this->_useTLS            = $useTLS; 
     223        $this->_options           = $options; 
     224 
     225        /* Try to include the Auth_SASL package.  If the package is not 
     226         * available, we disable the authentication methods that depend upon 
     227         * it. */ 
     228        if ((@include_once 'Auth/SASL.php') === false) { 
     229            $this->_debug('Auth_SASL not present'); 
     230            foreach ($this->supportedSASLAuthMethods as $SASLMethod) { 
     231                $pos = array_search($SASLMethod, $this->supportedAuthMethods); 
     232                $this->_debug('Disabling method ' . $SASLMethod); 
     233                unset($this->supportedAuthMethods[$pos]); 
     234            } 
     235        } 
     236 
     237        if (strlen($user) && strlen($pass)) { 
     238            $this->_error = $this->_handleConnectAndLogin(); 
     239        } 
     240    } 
     241 
     242    /** 
     243     * Returns any error that may have been generated in the constructor. 
     244     * 
     245     * @return boolean|PEAR_Error  False if no error, PEAR_Error otherwise. 
     246     */ 
     247    function getError() 
     248    { 
     249        return PEAR::isError($this->_error) ? $this->_error : false; 
     250    } 
     251 
     252    /** 
     253     * Sets the debug state and handler function. 
     254     * 
     255     * @param boolean $debug   Whether to enable debugging. 
     256     * @param string  $handler A custom debug handler. Must be a valid callback. 
     257     * 
     258     * @return void 
     259     */ 
     260    function setDebug($debug = true, $handler = null) 
     261    { 
    178262        $this->_debug = $debug; 
    179         $this->_bypassAuth = $bypassAuth; 
    180         $this->_useTLS = $useTLS; 
    181         $this->_options = $options; 
    182         /* 
    183         * Include the Auth_SASL package.  If the package is not available, 
    184         * we disable the authentication methods that depend upon it. 
    185         */ 
    186         if ((@include_once 'Auth/SASL.php') === false) { 
    187             if($this->_debug){ 
    188                 echo "AUTH_SASL NOT PRESENT!\n"; 
    189             } 
    190             foreach($this->supportedSASLAuthMethods as $SASLMethod){ 
    191                 $pos = array_search( $SASLMethod, $this->supportedAuthMethods ); 
    192                 if($this->_debug){ 
    193                     echo "DISABLING METHOD $SASLMethod\n"; 
    194                 } 
    195                 unset($this->supportedAuthMethods[$pos]); 
    196             } 
    197         } 
    198         if( ($user != null) && ($pass != null) ){ 
    199             $this->_error = $this->_handleConnectAndLogin(); 
    200         } 
    201     } 
    202  
    203     /** 
    204     * Handles the errors the class can find 
    205     * on the server 
    206     * 
    207     * @access private 
    208     * @param mixed $msg  Text error message or PEAR error object 
    209     * @param integer $code  Numeric error code 
    210     * @return PEAR_Error 
    211     */ 
    212     function _raiseError($msg, $code) 
    213     { 
    214         include_once 'PEAR.php'; 
    215         return PEAR::raiseError($msg, $code); 
    216     } 
    217  
    218     /** 
    219     * Handles connect and login. 
    220     * on the server 
    221     * 
    222     * @access private 
    223     * @return mixed Indexed array of scriptnames or PEAR_Error on failure 
    224     */ 
     263        $this->_debug_handler = $handler; 
     264    } 
     265 
     266    /** 
     267     * Connects to the server and logs in. 
     268     * 
     269     * @return boolean  True on success, PEAR_Error on failure. 
     270     */ 
    225271    function _handleConnectAndLogin() 
    226272    { 
    227         if (PEAR::isError($res = $this->connect($this->_data['host'] , $this->_data['port'], $this->_options, $this->_useTLS ))) { 
     273        if (PEAR::isError($res = $this->connect($this->_data['host'], $this->_data['port'], $this->_options, $this->_useTLS))) { 
    228274            return $res; 
    229275        } 
    230         if($this->_bypassAuth === false) { 
    231            if (PEAR::isError($res = $this->login($this->_data['user'], $this->_data['pass'], $this->_data['logintype'] , $this->_data['euser'] , $this->_bypassAuth) ) ) { 
     276        if ($this->_bypassAuth === false) { 
     277            if (PEAR::isError($res = $this->login($this->_data['user'], $this->_data['pass'], $this->_data['logintype'], $this->_data['euser'], $this->_bypassAuth))) { 
    232278                return $res; 
    233279            } 
     
    237283 
    238284    /** 
    239     * Returns an indexed array of scripts currently 
    240     * on the server 
    241     * 
    242     * @return mixed Indexed array of scriptnames or PEAR_Error on failure 
    243     */ 
     285     * Handles connecting to the server and checks the response validity. 
     286     * 
     287     * @param string  $host    Hostname of server. 
     288     * @param string  $port    Port of server. 
     289     * @param array   $options List of options to pass to 
     290     *                         stream_context_create(). 
     291     * @param boolean $useTLS  Use TLS if available. 
     292     * 
     293     * @return boolean  True on success, PEAR_Error otherwise. 
     294     */ 
     295    function connect($host, $port, $options = null, $useTLS = true) 
     296    { 
     297        if (NET_SIEVE_STATE_DISCONNECTED != $this->_state) { 
     298            return PEAR::raiseError('Not currently in DISCONNECTED state', 1); 
     299        } 
     300 
     301        if (PEAR::isError($res = $this->_sock->connect($host, $port, false, 5, $options))) { 
     302            return $res; 
     303        } 
     304 
     305        if ($this->_bypassAuth) { 
     306            $this->_state = NET_SIEVE_STATE_TRANSACTION; 
     307        } else { 
     308            $this->_state = NET_SIEVE_STATE_AUTHORISATION; 
     309            if (PEAR::isError($res = $this->_doCmd())) { 
     310                return $res; 
     311            } 
     312        } 
     313 
     314        // Explicitly ask for the capabilities in case the connection is 
     315        // picked up from an existing connection. 
     316        if (PEAR::isError($res = $this->_cmdCapability())) { 
     317            return PEAR::raiseError( 
     318                'Failed to connect, server said: ' . $res->getMessage(), 2 
     319            ); 
     320        } 
     321 
     322        // Check if we can enable TLS via STARTTLS. 
     323        if ($useTLS && !empty($this->_capability['starttls']) 
     324            && function_exists('stream_socket_enable_crypto') 
     325        ) { 
     326            if (PEAR::isError($res = $this->_startTLS())) { 
     327                return $res; 
     328            } 
     329        } 
     330 
     331        return true; 
     332    } 
     333 
     334    /** 
     335     * Disconnect from the Sieve server. 
     336     * 
     337     * @param boolean $sendLogoutCMD Whether to send LOGOUT command before 
     338     *                               disconnecting. 
     339     * 
     340     * @return boolean  True on success, PEAR_Error otherwise. 
     341     */ 
     342    function disconnect($sendLogoutCMD = true) 
     343    { 
     344        return $this->_cmdLogout($sendLogoutCMD); 
     345    } 
     346 
     347    /** 
     348     * Logs into server. 
     349     * 
     350     * @param string  $user       Login username. 
     351     * @param string  $pass       Login password. 
     352     * @param string  $logintype  Type of login method to use. 
     353     * @param string  $euser      Effective UID (perform on behalf of $euser). 
     354     * @param boolean $bypassAuth Do not perform authentication. 
     355     * 
     356     * @return boolean  True on success, PEAR_Error otherwise. 
     357     */ 
     358    function login($user, $pass, $logintype = null, $euser = '', $bypassAuth = false) 
     359    { 
     360        if (NET_SIEVE_STATE_AUTHORISATION != $this->_state) { 
     361            return PEAR::raiseError('Not currently in AUTHORISATION state', 1); 
     362        } 
     363 
     364        if (!$bypassAuth ) { 
     365            if (PEAR::isError($res = $this->_cmdAuthenticate($user, $pass, $logintype, $euser))) { 
     366                return $res; 
     367            } 
     368        } 
     369        $this->_state = NET_SIEVE_STATE_TRANSACTION; 
     370 
     371        return true; 
     372    } 
     373 
     374    /** 
     375     * Returns an indexed array of scripts currently on the server. 
     376     * 
     377     * @return array  Indexed array of scriptnames. 
     378     */ 
    244379    function listScripts() 
    245380    { 
     
    253388 
    254389    /** 
    255     * Returns the active script 
    256     * 
    257     * @return mixed The active scriptname or PEAR_Error on failure 
    258     */ 
     390     * Returns the active script. 
     391     * 
     392     * @return string  The active scriptname. 
     393     */ 
    259394    function getActive() 
    260395    { 
    261396        if (!empty($this->_active)) { 
    262397            return $this->_active; 
    263  
    264         } elseif (is_array($scripts = $this->_cmdListScripts())) { 
     398        } 
     399        if (is_array($scripts = $this->_cmdListScripts())) { 
    265400            $this->_active = $scripts[1]; 
    266401            return $scripts[1]; 
     
    269404 
    270405    /** 
    271     * Sets the active script 
    272     * 
    273     * @param  string $scriptname The name of the script to be set as active 
    274     * @return mixed              true on success, PEAR_Error on failure 
    275     */ 
     406     * Sets the active script. 
     407     * 
     408     * @param string $scriptname The name of the script to be set as active. 
     409     * 
     410     * @return boolean  True on success, PEAR_Error on failure. 
     411     */ 
    276412    function setActive($scriptname) 
    277413    { 
     
    280416 
    281417    /** 
    282     * Retrieves a script 
    283     * 
    284     * @param  string $scriptname The name of the script to be retrieved 
    285     * @return mixed              The script on success, PEAR_Error on failure 
     418     * Retrieves a script. 
     419     * 
     420     * @param string $scriptname The name of the script to be retrieved. 
     421     * 
     422     * @return string  The script on success, PEAR_Error on failure. 
    286423    */ 
    287424    function getScript($scriptname) 
     
    291428 
    292429    /** 
    293     * Adds a script to the server 
    294     * 
    295     * @param  string $scriptname Name of the script 
    296     * @param  string $script     The script 
    297     * @param  boolean $makeactive Whether to make this the active script 
    298     * @return mixed              true on success, PEAR_Error on failure 
    299     */ 
     430     * Adds a script to the server. 
     431     * 
     432     * @param string  $scriptname Name of the script. 
     433     * @param string  $script     The script content. 
     434     * @param boolean $makeactive Whether to make this the active script. 
     435     * 
     436     * @return boolean  True on success, PEAR_Error on failure. 
     437     */ 
    300438    function installScript($scriptname, $script, $makeactive = false) 
    301439    { 
    302440        if (PEAR::isError($res = $this->_cmdPutScript($scriptname, $script))) { 
    303441            return $res; 
    304  
    305         } elseif ($makeactive) { 
     442        } 
     443        if ($makeactive) { 
    306444            return $this->_cmdSetActive($scriptname); 
    307  
    308         } else { 
    309             return true; 
    310         } 
    311     } 
    312  
    313     /** 
    314     * Removes a script from the server 
    315     * 
    316     * @param  string $scriptname Name of the script 
    317     * @return mixed              True on success, PEAR_Error on failure 
    318     */ 
     445        } 
     446        return true; 
     447    } 
     448 
     449    /** 
     450     * Removes a script from the server. 
     451     * 
     452     * @param string $scriptname Name of the script. 
     453     * 
     454     * @return boolean  True on success, PEAR_Error on failure. 
     455     */ 
    319456    function removeScript($scriptname) 
    320457    { 
     
    323460 
    324461    /** 
    325     * Returns any error that may have been generated in the 
    326     * constructor 
    327     * 
    328     * @return mixed False if no error, PEAR_Error otherwise 
    329     */ 
    330     function getError() 
    331     { 
    332         return PEAR::isError($this->_error) ? $this->_error : false; 
    333     } 
    334  
    335     /** 
    336     * Handles connecting to the server and checking the 
    337     * response is valid. 
    338     * 
    339     * @access private 
    340     * @param  string $host Hostname of server 
    341     * @param  string $port Port of server 
    342     * @param  array  $options List of options to pass to connect 
    343     * @param  boolean $useTLS Use TLS if available 
    344     * @return mixed        True on success, PEAR_Error otherwise 
    345     */ 
    346     function connect($host, $port, $options = null, $useTLS = true) 
    347     { 
    348         if (NET_SIEVE_STATE_DISCONNECTED != $this->_state) { 
    349             $msg='Not currently in DISCONNECTED state'; 
    350             $code=1; 
    351             return $this->_raiseError($msg,$code); 
    352         } 
    353  
    354         if (PEAR::isError($res = $this->_sock->connect($host, $port, false, 5, $options))) { 
     462     * Checks if the server has space to store the script by the server. 
     463     * 
     464     * @param string  $scriptname The name of the script to mark as active. 
     465     * @param integer $size       The size of the script. 
     466     * 
     467     * @return boolean|PEAR_Error  True if there is space, PEAR_Error otherwise. 
     468     * 
     469     * @todo Rename to hasSpace() 
     470     */ 
     471    function haveSpace($scriptname, $size) 
     472    { 
     473        if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
     474            return PEAR::raiseError('Not currently in TRANSACTION state', 1); 
     475        } 
     476        if (PEAR::isError($res = $this->_doCmd(sprintf('HAVESPACE "%s" %d', $scriptname, $size)))) { 
    355477            return $res; 
    356478        } 
    357  
    358         if($this->_bypassAuth === false) { 
    359             $this->_state = NET_SIEVE_STATE_AUTHORISATION; 
    360             if (PEAR::isError($res = $this->_doCmd())) { 
    361                 return $res; 
    362             } 
    363         } else { 
    364             $this->_state = NET_SIEVE_STATE_TRANSACTION; 
    365         } 
    366  
    367         // Explicitly ask for the capabilities in case the connection 
    368         // is picked up from an existing connection. 
    369         if(PEAR::isError($res = $this->_cmdCapability() )) { 
    370             $msg='Failed to connect, server said: ' . $res->getMessage(); 
    371             $code=2; 
    372             return $this->_raiseError($msg,$code); 
    373         } 
    374  
    375         if($useTLS === true) { 
    376             // check if we can enable TLS via STARTTLS 
    377             if(isset($this->_capability['starttls']) && function_exists('stream_socket_enable_crypto') === true) { 
    378                 if (PEAR::isError($res = $this->_startTLS())) { 
    379                     return $res; 
     479        return true; 
     480    } 
     481 
     482    /** 
     483     * Returns the list of extensions the server supports. 
     484     * 
     485     * @return array  List of extensions or PEAR_Error on failure. 
     486     */ 
     487    function getExtensions() 
     488    { 
     489        if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { 
     490            return PEAR::raiseError('Not currently connected', 7); 
     491        } 
     492        return $this->_capability['extensions']; 
     493    } 
     494 
     495    /** 
     496     * Returns whether the server supports an extension. 
     497     * 
     498     * @param string $extension The extension to check. 
     499     * 
     500     * @return boolean  Whether the extension is supported or PEAR_Error on 
     501     *                  failure. 
     502     */ 
     503    function hasExtension($extension) 
     504    { 
     505        if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { 
     506            return PEAR::raiseError('Not currently connected', 7); 
     507        } 
     508 
     509        $extension = trim($this->_toUpper($extension)); 
     510        if (is_array($this->_capability['extensions'])) { 
     511            foreach ($this->_capability['extensions'] as $ext) { 
     512                if ($ext == $extension) { 
     513                    return true; 
    380514                } 
    381515            } 
    382516        } 
    383517 
     518        return false; 
     519    } 
     520 
     521    /** 
     522     * Returns the list of authentication methods the server supports. 
     523     * 
     524     * @return array  List of authentication methods or PEAR_Error on failure. 
     525     */ 
     526    function getAuthMechs() 
     527    { 
     528        if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { 
     529            return PEAR::raiseError('Not currently connected', 7); 
     530        } 
     531        return $this->_capability['sasl']; 
     532    } 
     533 
     534    /** 
     535     * Returns whether the server supports an authentication method. 
     536     * 
     537     * @param string $method The method to check. 
     538     * 
     539     * @return boolean  Whether the method is supported or PEAR_Error on 
     540     *                  failure. 
     541     */ 
     542    function hasAuthMech($method) 
     543    { 
     544        if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { 
     545            return PEAR::raiseError('Not currently connected', 7); 
     546        } 
     547 
     548        $method = trim($this->_toUpper($method)); 
     549        if (is_array($this->_capability['sasl'])) { 
     550            foreach ($this->_capability['sasl'] as $sasl) { 
     551                if ($sasl == $method) { 
     552                    return true; 
     553                } 
     554            } 
     555        } 
     556 
     557        return false; 
     558    } 
     559 
     560    /** 
     561     * Handles the authentication using any known method. 
     562     * 
     563     * @param string $uid        The userid to authenticate as. 
     564     * @param string $pwd        The password to authenticate with. 
     565     * @param string $userMethod The method to use. If empty, the class chooses 
     566     *                           the best (strongest) available method. 
     567     * @param string $euser      The effective uid to authenticate as. 
     568     * 
     569     * @return void 
     570     */ 
     571    function _cmdAuthenticate($uid, $pwd, $userMethod = null, $euser = '') 
     572    { 
     573        if (PEAR::isError($method = $this->_getBestAuthMethod($userMethod))) { 
     574            return $method; 
     575        } 
     576        switch ($method) { 
     577        case 'DIGEST-MD5': 
     578            return $this->_authDigestMD5($uid, $pwd, $euser); 
     579        case 'CRAM-MD5': 
     580            $result = $this->_authCRAMMD5($uid, $pwd, $euser); 
     581            break; 
     582        case 'LOGIN': 
     583            $result = $this->_authLOGIN($uid, $pwd, $euser); 
     584            break; 
     585        case 'PLAIN': 
     586            $result = $this->_authPLAIN($uid, $pwd, $euser); 
     587            break; 
     588        case 'EXTERNAL': 
     589            $result = $this->_authEXTERNAL($uid, $pwd, $euser); 
     590            break; 
     591        default : 
     592            $result = PEAR::raiseError( 
     593                $method . ' is not a supported authentication method' 
     594            ); 
     595            break; 
     596        } 
     597 
     598        if (PEAR::isError($res = $this->_doCmd())) { 
     599            return $res; 
     600        } 
     601 
     602        return $result; 
     603    } 
     604 
     605    /** 
     606     * Authenticates the user using the PLAIN method. 
     607     * 
     608     * @param string $user  The userid to authenticate as. 
     609     * @param string $pass  The password to authenticate with. 
     610     * @param string $euser The effective uid to authenticate as. 
     611     * 
     612     * @return void 
     613     */ 
     614    function _authPLAIN($user, $pass, $euser) 
     615    { 
     616        return $this->_sendCmd( 
     617            sprintf( 
     618                'AUTHENTICATE "PLAIN" "%s"', 
     619                base64_encode($euser . chr(0) . $user . chr(0) . $pass) 
     620            ) 
     621        ); 
     622    } 
     623 
     624    /** 
     625     * Authenticates the user using the LOGIN method. 
     626     * 
     627     * @param string $user  The userid to authenticate as. 
     628     * @param string $pass  The password to authenticate with. 
     629     * @param string $euser The effective uid to authenticate as. 
     630     * 
     631     * @return void 
     632     */ 
     633    function _authLOGIN($user, $pass, $euser) 
     634    { 
     635        if (PEAR::isError($result = $this->_sendCmd('AUTHENTICATE "LOGIN"'))) { 
     636            return $result; 
     637        } 
     638        if (PEAR::isError($result = $this->_doCmd('"' . base64_encode($user) . '"'))) { 
     639            return $result; 
     640        } 
     641        return $this->_doCmd('"' . base64_encode($pass) . '"'); 
     642    } 
     643 
     644    /** 
     645     * Authenticates the user using the CRAM-MD5 method. 
     646     * 
     647     * @param string $user  The userid to authenticate as. 
     648     * @param string $pass  The password to authenticate with. 
     649     * @param string $euser The effective uid to authenticate as. 
     650     * 
     651     * @return void 
     652     */ 
     653    function _authCRAMMD5($user, $pass, $euser) 
     654    { 
     655        if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "CRAM-MD5"', true))) { 
     656            return $challenge; 
     657        } 
     658 
     659        $challenge = base64_decode(trim($challenge)); 
     660        $cram = Auth_SASL::factory('crammd5'); 
     661        if (PEAR::isError($response = $cram->getResponse($user, $pass, $challenge))) { 
     662            return $response; 
     663        } 
     664 
     665        return $this->_sendStringResponse(base64_encode($response)); 
     666    } 
     667 
     668    /** 
     669     * Authenticates the user using the DIGEST-MD5 method. 
     670     * 
     671     * @param string $user  The userid to authenticate as. 
     672     * @param string $pass  The password to authenticate with. 
     673     * @param string $euser The effective uid to authenticate as. 
     674     * 
     675     * @return void 
     676     */ 
     677    function _authDigestMD5($user, $pass, $euser) 
     678    { 
     679        if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "DIGEST-MD5"', true))) { 
     680            return $challenge; 
     681        } 
     682 
     683        $challenge = base64_decode(trim($challenge)); 
     684        $digest = Auth_SASL::factory('digestmd5'); 
     685        // @todo Really 'localhost'? 
     686        if (PEAR::isError($response = $digest->getResponse($user, $pass, $challenge, 'localhost', 'sieve', $euser))) { 
     687            return $response; 
     688        } 
     689 
     690        if (PEAR::isError($result = $this->_sendStringResponse(base64_encode($param)))) { 
     691            return $result; 
     692        } 
     693        if (PEAR::isError($result = $this->_doCmd())) { 
     694            return $result; 
     695        } 
     696        if ($this->_toUpper(substr($result, 0, 2)) == 'OK') { 
     697            return; 
     698        } 
     699 
     700        /* We don't use the protocol's third step because SIEVE doesn't allow 
     701         * subsequent authentication, so we just silently ignore it. */ 
     702        if (PEAR::isError($result = $this->_sendStringResponse(''))) { 
     703            return $result; 
     704        } 
     705 
     706        return $this->_doCmd(); 
     707    } 
     708 
     709    /** 
     710     * Authenticates the user using the EXTERNAL method. 
     711     * 
     712     * @param string $user  The userid to authenticate as. 
     713     * @param string $pass  The password to authenticate with. 
     714     * @param string $euser The effective uid to authenticate as. 
     715     * 
     716     * @return void 
     717     * 
     718     * @since  1.1.7 
     719     */ 
     720    function _authEXTERNAL($user, $pass, $euser) 
     721    { 
     722        $cmd = sprintf( 
     723            'AUTHENTICATE "EXTERNAL" "%s"', 
     724            base64_encode(strlen($euser) ? $euser : $user) 
     725        ); 
     726        return $this->_sendCmd($cmd); 
     727    } 
     728 
     729    /** 
     730     * Removes a script from the server. 
     731     * 
     732     * @param string $scriptname Name of the script to delete. 
     733     * 
     734     * @return boolean  True on success, PEAR_Error otherwise. 
     735     */ 
     736    function _cmdDeleteScript($scriptname) 
     737    { 
     738        if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
     739            return PEAR::raiseError('Not currently in AUTHORISATION state', 1); 
     740        } 
     741        if (PEAR::isError($res = $this->_doCmd(sprintf('DELETESCRIPT "%s"', $scriptname)))) { 
     742            return $res; 
     743        } 
    384744        return true; 
    385745    } 
    386746 
    387747    /** 
    388     * Logs into server. 
    389     * 
    390     * @param  string  $user          Login username 
    391     * @param  string  $pass          Login password 
    392     * @param  string  $logintype     Type of login method to use 
    393     * @param  string  $euser         Effective UID (perform on behalf of $euser) 
    394     * @param  boolean $bypassAuth    Do not perform authentication 
    395     * @return mixed                  True on success, PEAR_Error otherwise 
    396     */ 
    397     function login($user, $pass, $logintype = null , $euser = '', $bypassAuth = false) 
    398     { 
    399         if (NET_SIEVE_STATE_AUTHORISATION != $this->_state) { 
    400             $msg='Not currently in AUTHORISATION state'; 
    401             $code=1; 
    402             return $this->_raiseError($msg,$code); 
    403         } 
    404  
    405         if( $bypassAuth === false ){ 
    406             if(PEAR::isError($res=$this->_cmdAuthenticate($user , $pass , $logintype, $euser ) ) ){ 
    407                 return $res; 
    408             } 
    409         } 
    410         $this->_state = NET_SIEVE_STATE_TRANSACTION; 
    411         return true; 
    412     } 
    413  
    414     /** 
    415      * Handles the authentication using any known method 
    416      * 
    417      * @param string $uid The userid to authenticate as. 
    418      * @param string $pwd The password to authenticate with. 
    419      * @param string $userMethod The method to use ( if $userMethod == '' then the class chooses the best method (the stronger is the best ) ) 
    420      * @param string $euser The effective uid to authenticate as. 
    421      * 
    422      * @return mixed  string or PEAR_Error 
    423      * 
    424      * @access private 
    425      * @since  1.0 
    426      */ 
    427     function _cmdAuthenticate($uid , $pwd , $userMethod = null , $euser = '' ) 
    428     { 
    429         if ( PEAR::isError( $method = $this->_getBestAuthMethod($userMethod) ) ) { 
    430             return $method; 
    431         } 
    432         switch ($method) { 
    433             case 'DIGEST-MD5': 
    434                 $result = $this->_authDigest_MD5( $uid , $pwd , $euser ); 
    435                 return $result; 
    436                 break; 
    437             case 'CRAM-MD5': 
    438                 $result = $this->_authCRAM_MD5( $uid , $pwd, $euser); 
    439                 break; 
    440             case 'LOGIN': 
    441                 $result = $this->_authLOGIN( $uid , $pwd , $euser ); 
    442                 break; 
    443             case 'PLAIN': 
    444                 $result = $this->_authPLAIN( $uid , $pwd , $euser ); 
    445                 break; 
    446             case 'EXTERNAL': 
    447                 $result = $this->_authEXTERNAL( $uid , $pwd , $euser ); 
    448                 break; 
    449             default : 
    450                 $result = new PEAR_Error( "$method is not a supported authentication method" ); 
    451                 break; 
    452         } 
    453  
    454         if (PEAR::isError($res = $this->_doCmd() )) { 
     748     * Retrieves the contents of the named script. 
     749     * 
     750     * @param string $scriptname Name of the script to retrieve. 
     751     * 
     752     * @return string  The script if successful, PEAR_Error otherwise. 
     753     */ 
     754    function _cmdGetScript($scriptname) 
     755    { 
     756        if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
     757            return PEAR::raiseError('Not currently in AUTHORISATION state', 1); 
     758        } 
     759 
     760        if (PEAR::isError($res = $this->_doCmd(sprintf('GETSCRIPT "%s"', $scriptname)))) { 
    455761            return $res; 
    456762        } 
    457         return $result; 
    458     } 
    459  
    460     /** 
    461      * Authenticates the user using the PLAIN method. 
    462      * 
    463      * @param string $user The userid to authenticate as. 
    464      * @param string $pass The password to authenticate with. 
    465      * @param string $euser The effective uid to authenticate as. 
    466      * 
    467      * @return array Returns an array containing the response 
    468      * 
    469      * @access private 
    470      * @since  1.0 
    471      */ 
    472     function _authPLAIN($user, $pass , $euser ) 
    473     { 
    474         if ($euser != '') { 
    475             $cmd=sprintf('AUTHENTICATE "PLAIN" "%s"', base64_encode($euser . chr(0) . $user . chr(0) . $pass ) ) ; 
    476         } else { 
    477             $cmd=sprintf('AUTHENTICATE "PLAIN" "%s"', base64_encode( chr(0) . $user . chr(0) . $pass ) ); 
    478         } 
    479         return  $this->_sendCmd( $cmd ) ; 
    480     } 
    481  
    482     /** 
    483      * Authenticates the user using the PLAIN method. 
    484      * 
    485      * @param string $user The userid to authenticate as. 
    486      * @param string $pass The password to authenticate with. 
    487      * @param string $euser The effective uid to authenticate as. 
    488      * 
    489      * @return array Returns an array containing the response 
    490      * 
    491      * @access private 
    492      * @since  1.0 
    493      */ 
    494     function _authLOGIN($user, $pass , $euser ) 
    495     { 
    496         $this->_sendCmd('AUTHENTICATE "LOGIN"'); 
    497         $this->_doCmd(sprintf('"%s"', base64_encode($user))); 
    498         $this->_doCmd(sprintf('"%s"', base64_encode($pass))); 
    499     } 
    500  
    501     /** 
    502      * Authenticates the user using the CRAM-MD5 method. 
    503      * 
    504      * @param string $uid The userid to authenticate as. 
    505      * @param string $pwd The password to authenticate with. 
    506      * @param string $euser The effective uid to authenticate as. 
    507      * 
    508      * @return array Returns an array containing the response 
    509      * 
    510      * @access private 
    511      * @since  1.0 
    512      */ 
    513     function _authCRAM_MD5($uid, $pwd, $euser) 
    514     { 
    515         if ( PEAR::isError( $challenge = $this->_doCmd( 'AUTHENTICATE "CRAM-MD5"' ) ) ) { 
    516             $this->_error=$challenge; 
    517             return $challenge; 
    518         } 
    519         $challenge=trim($challenge); 
    520         $challenge = base64_decode( trim($challenge) ); 
    521         $cram = &Auth_SASL::factory('crammd5'); 
    522         if ( PEAR::isError($resp=$cram->getResponse( $uid , $pwd , $challenge ) ) ) { 
    523             $this->_error=$resp; 
    524             return $resp; 
    525         } 
    526         $auth_str = base64_encode( $resp ); 
    527         if ( PEAR::isError($error = $this->_sendStringResponse( $auth_str  ) ) ) { 
    528             $this->_error=$error; 
    529             return $error; 
    530         } 
    531  
    532     } 
    533  
    534     /** 
    535      * Authenticates the user using the DIGEST-MD5 method. 
    536      * 
    537      * @param string $uid The userid to authenticate as. 
    538      * @param string $pwd The password to authenticate with. 
    539      * @param string $euser The effective uid to authenticate as. 
    540      * 
    541      * @return array Returns an array containing the response 
    542      * 
    543      * @access private 
    544      * @since  1.0 
    545      */ 
    546     function _authDigest_MD5($uid, $pwd, $euser) 
    547     { 
    548         if ( PEAR::isError( $challenge = $this->_doCmd('AUTHENTICATE "DIGEST-MD5"') ) ) { 
    549             $this->_error= $challenge; 
    550             return $challenge; 
    551         } 
    552         $challenge = base64_decode( $challenge ); 
    553         $digest = &Auth_SASL::factory('digestmd5'); 
    554  
    555         if(PEAR::isError($param=$digest->getResponse($uid, $pwd, $challenge, "localhost", "sieve" , $euser) )) { 
    556             return $param; 
    557         } 
    558         $auth_str = base64_encode($param); 
    559  
    560         if ( PEAR::isError($error = $this->_sendStringResponse( $auth_str  ) ) ) { 
    561             $this->_error=$error; 
    562             return $error; 
    563         } 
    564  
    565         if ( PEAR::isError( $challenge = $this->_doCmd() ) ) { 
    566             $this->_error=$challenge ; 
    567             return $challenge ; 
    568         } 
    569  
    570         if( strtoupper(substr($challenge,0,2))== 'OK' ){ 
    571                 return true; 
    572         } 
    573  
    574         /** 
    575         * We don't use the protocol's third step because SIEVE doesn't allow 
    576         * subsequent authentication, so we just silently ignore it. 
    577         */ 
    578         if ( PEAR::isError($error = $this->_sendStringResponse( '' ) ) ) { 
    579             $this->_error=$error; 
    580             return $error; 
    581         } 
    582  
    583         if (PEAR::isError($res = $this->_doCmd() )) { 
    584             return $res; 
    585         } 
    586     } 
    587  
    588      /** 
    589      * Authenticates the user using the EXTERNAL method. 
    590      * 
    591      * @param string $user The userid to authenticate as. 
    592      * @param string $pass The password to authenticate with. 
    593      * @param string $euser The effective uid to authenticate as. 
    594      * 
    595      * @return array Returns an array containing the response 
    596      * 
    597      * @access private 
    598      * @since  1.1.7 
    599      */ 
    600     function _authEXTERNAL($user, $pass, $euser) 
    601     { 
    602         if ($euser != '') { 
    603             $cmd=sprintf('AUTHENTICATE "EXTERNAL" "%s"', base64_encode($euser) ) ; 
    604         } else { 
    605             $cmd=sprintf('AUTHENTICATE "EXTERNAL" "%s"', base64_encode($user) ); 
    606         } 
    607         return $this->_sendCmd( $cmd ) ; 
    608     } 
    609  
    610     /** 
    611     * Removes a script from the server 
    612     * 
    613     * @access private 
    614     * @param  string $scriptname Name of the script to delete 
    615     * @return mixed              True on success, PEAR_Error otherwise 
    616     */ 
    617     function _cmdDeleteScript($scriptname) 
    618     { 
    619         if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
    620             $msg='Not currently in AUTHORISATION state'; 
    621             $code=1; 
    622             return $this->_raiseError($msg,$code); 
    623         } 
    624         if (PEAR::isError($res = $this->_doCmd(sprintf('DELETESCRIPT "%s"', $scriptname) ) )) { 
    625             return $res; 
    626         } 
    627         return true; 
    628     } 
    629  
    630     /** 
    631     * Retrieves the contents of the named script 
    632     * 
    633     * @access private 
    634     * @param  string $scriptname Name of the script to retrieve 
    635     * @return mixed              The script if successful, PEAR_Error otherwise 
    636     */ 
    637     function _cmdGetScript($scriptname) 
    638     { 
    639         if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
    640             $msg='Not currently in AUTHORISATION state'; 
    641             $code=1; 
    642             return $this->_raiseError($msg,$code); 
    643         } 
    644  
    645         if (PEAR::isError($res = $this->_doCmd(sprintf('GETSCRIPT "%s"', $scriptname) ) ) ) { 
    646             return $res; 
    647         } 
    648763 
    649764        return preg_replace('/{[0-9]+}\r\n/', '', $res); 
     
    651766 
    652767    /** 
    653     * Sets the ACTIVE script, ie the one that gets run on new mail 
    654     * by the server 
    655     * 
    656     * @access private 
    657     * @param  string $scriptname The name of the script to mark as active 
    658     * @return mixed              True on success, PEAR_Error otherwise 
     768     * Sets the active script, i.e. the one that gets run on new mail by the 
     769     * server. 
     770     * 
     771     * @param string $scriptname The name of the script to mark as active. 
     772     * 
     773     * @return boolean  True on success, PEAR_Error otherwise. 
    659774    */ 
    660775    function _cmdSetActive($scriptname) 
    661776    { 
    662777        if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
    663             $msg='Not currently in AUTHORISATION state'; 
    664             $code=1; 
    665             return $this->_raiseError($msg,$code); 
    666         } 
    667  
    668         if (PEAR::isError($res = $this->_doCmd(sprintf('SETACTIVE "%s"', $scriptname) ) ) ) { 
     778            return PEAR::raiseError('Not currently in AUTHORISATION state', 1); 
     779        } 
     780        if (PEAR::isError($res = $this->_doCmd(sprintf('SETACTIVE "%s"', $scriptname)))) { 
    669781            return $res; 
    670782        } 
    671  
    672783        $this->_activeScript = $scriptname; 
    673784        return true; 
     
    675786 
    676787    /** 
    677     * Sends the LISTSCRIPTS command 
    678     * 
    679     * @access private 
    680     * @return mixed Two item array of scripts, and active script on success, 
    681     *               PEAR_Error otherwise. 
    682     */ 
     788     * Returns the list of scripts on the server. 
     789     * 
     790     * @return array  An array with the list of scripts in the first element 
     791     *                and the active script in the second element on success, 
     792     *                PEAR_Error otherwise. 
     793     */ 
    683794    function _cmdListScripts() 
    684795    { 
    685796        if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
    686             $msg='Not currently in AUTHORISATION state'; 
    687             $code=1; 
    688             return $this->_raiseError($msg,$code); 
     797            return PEAR::raiseError('Not currently in AUTHORISATION state', 1); 
     798        } 
     799 
     800        if (PEAR::isError($res = $this->_doCmd('LISTSCRIPTS'))) { 
     801            return $res; 
    689802        } 
    690803 
    691804        $scripts = array(); 
    692805        $activescript = null; 
    693  
    694         if (PEAR::isError($res = $this->_doCmd('LISTSCRIPTS'))) { 
    695             return $res; 
    696         } 
    697  
    698806        $res = explode("\r\n", $res); 
    699  
    700807        foreach ($res as $value) { 
    701808            if (preg_match('/^"(.*)"( ACTIVE)?$/i', $value, $matches)) { 
     
    711818 
    712819    /** 
    713     * Sends the PUTSCRIPT command to add a script to 
    714     * the server. 
    715     * 
    716     * @access private 
    717     * @param  string $scriptname Name of the new script 
    718     * @param  string $scriptdata The new script 
    719     * @return mixed              True on success, PEAR_Error otherwise 
    720     */ 
     820     * Adds a script to the server. 
     821     * 
     822     * @param string $scriptname Name of the new script. 
     823     * @param string $scriptdata The new script. 
     824     * 
     825     * @return boolean  True on success, PEAR_Error otherwise. 
     826     */ 
    721827    function _cmdPutScript($scriptname, $scriptdata) 
    722828    { 
    723829        if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
    724             $msg='Not currently in TRANSACTION state'; 
    725             $code=1; 
    726             return $this->_raiseError($msg,$code); 
     830            return PEAR::raiseError('Not currently in AUTHORISATION state', 1); 
    727831        } 
    728832 
    729833        $stringLength = $this->_getLineLength($scriptdata); 
    730834 
    731         if (PEAR::isError($res = $this->_doCmd(sprintf("PUTSCRIPT \"%s\" {%d+}\r\n%s", $scriptname, $stringLength, $scriptdata) ))) { 
     835        if (PEAR::isError($res = $this->_doCmd(sprintf("PUTSCRIPT \"%s\" {%d+}\r\n%s", $scriptname, $stringLength, $scriptdata)))) { 
    732836            return $res; 
    733837        } 
     
    737841 
    738842    /** 
    739     * Sends the LOGOUT command and terminates the connection 
    740     * 
    741     * @access private 
    742     * @param boolean $sendLogoutCMD True to send LOGOUT command before disconnecting 
    743     * @return mixed True on success, PEAR_Error otherwise 
    744     */ 
    745     function _cmdLogout($sendLogoutCMD=true) 
    746     { 
    747         if (NET_SIEVE_STATE_DISCONNECTED === $this->_state) { 
    748             $msg='Not currently connected'; 
    749             $code=1; 
    750             return $this->_raiseError($msg,$code); 
    751             //return PEAR::raiseError('Not currently connected'); 
    752         } 
    753  
    754         if($sendLogoutCMD){ 
     843     * Logs out of the server and terminates the connection. 
     844     * 
     845     * @param boolean $sendLogoutCMD Whether to send LOGOUT command before 
     846     *                               disconnecting. 
     847     * 
     848     * @return boolean  True on success, PEAR_Error otherwise. 
     849     */ 
     850    function _cmdLogout($sendLogoutCMD = true) 
     851    { 
     852        if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { 
     853            return PEAR::raiseError('Not currently connected', 1); 
     854        } 
     855 
     856        if ($sendLogoutCMD) { 
    755857            if (PEAR::isError($res = $this->_doCmd('LOGOUT'))) { 
    756858                return $res; 
     
    760862        $this->_sock->disconnect(); 
    761863        $this->_state = NET_SIEVE_STATE_DISCONNECTED; 
     864 
    762865        return true; 
    763866    } 
    764867 
    765868    /** 
    766     * Sends the CAPABILITY command 
    767     * 
    768     * @access private 
    769     * @return mixed True on success, PEAR_Error otherwise 
    770     */ 
     869     * Sends the CAPABILITY command 
     870     * 
     871     * @return boolean  True on success, PEAR_Error otherwise. 
     872     */ 
    771873    function _cmdCapability() 
    772874    { 
    773         if (NET_SIEVE_STATE_DISCONNECTED === $this->_state) { 
    774             $msg='Not currently connected'; 
    775             $code=1; 
    776             return $this->_raiseError($msg,$code); 
    777         } 
    778  
     875        if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { 
     876            return PEAR::raiseError('Not currently connected', 1); 
     877        } 
    779878        if (PEAR::isError($res = $this->_doCmd('CAPABILITY'))) { 
    780879            return $res; 
     
    785884 
    786885    /** 
    787     * Checks if the server has space to store the script 
    788     * by the server 
    789     * 
    790     * @param  string $scriptname The name of the script to mark as active 
    791     * @param integer $size The size of the script 
    792     * @return mixed              True on success, PEAR_Error otherwise 
    793     */ 
    794     function haveSpace($scriptname,$size) 
    795     { 
    796         if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { 
    797             $msg='Not currently in TRANSACTION state'; 
    798             $code=1; 
    799             return $this->_raiseError($msg,$code); 
    800         } 
    801  
    802         if (PEAR::isError($res = $this->_doCmd(sprintf('HAVESPACE "%s" %d', $scriptname, $size) ) ) ) { 
    803             return $res; 
    804         } 
    805  
    806         return true; 
    807     } 
    808  
    809     /** 
    810     * Parses the response from the capability command. Stores 
    811     * the result in $this->_capability 
    812     * 
    813     * @access private 
    814     * @param string $data The response from the capability command 
    815     */ 
     886     * Parses the response from the CAPABILITY command and stores the result 
     887     * in $_capability. 
     888     * 
     889     * @param string $data The response from the capability command. 
     890     * 
     891     * @return void 
     892     */ 
    816893    function _parseCapability($data) 
    817894    { 
    818         // clear the cached capabilities 
    819         $this->_capability = array(); 
    820  
    821         $data = preg_split('/\r?\n/', $data, -1, PREG_SPLIT_NO_EMPTY); 
     895        // Clear the cached capabilities. 
     896        $this->_capability = array('sasl' => array(), 
     897                                   'extensions' => array()); 
     898 
     899        $data = preg_split('/\r?\n/', $this->_toUpper($data), -1, PREG_SPLIT_NO_EMPTY); 
    822900 
    823901        for ($i = 0; $i < count($data); $i++) { 
    824             if (preg_match('/^"([a-z]+)"( "(.*)")?$/i', $data[$i], $matches)) { 
    825                 switch (strtolower($matches[1])) { 
    826                     case 'implementation': 
    827                         $this->_capability['implementation'] = $matches[3]; 
    828                         break; 
    829  
    830                     case 'sasl': 
    831                         $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]); 
    832                         break; 
    833  
    834                     case 'sieve': 
    835                         $this->_capability['extensions'] = preg_split('/\s+/', $matches[3]); 
    836                         break; 
    837  
    838                     case 'starttls': 
    839                         $this->_capability['starttls'] = true; 
    840                         break; 
    841                 } 
    842             } 
    843         } 
    844     } 
    845  
    846     /** 
    847     * Sends a command to the server 
    848     * 
    849     * @access private 
    850     * @param string $cmd The command to send 
    851     */ 
     902            if (!preg_match('/^"([A-Z]+)"( "(.*)")?$/', $data[$i], $matches)) { 
     903                continue; 
     904            } 
     905            switch ($matches[1]) { 
     906            case 'IMPLEMENTATION': 
     907                $this->_capability['implementation'] = $matches[3]; 
     908                break; 
     909 
     910            case 'SASL': 
     911                $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]); 
     912                break; 
     913 
     914            case 'SIEVE': 
     915                $this->_capability['extensions'] = preg_split('/\s+/', $matches[3]); 
     916                break; 
     917 
     918            case 'STARTTLS': 
     919                $this->_capability['starttls'] = true; 
     920                break; 
     921            } 
     922        } 
     923    } 
     924 
     925    /** 
     926     * Sends a command to the server 
     927     * 
     928     * @param string $cmd The command to send. 
     929     * 
     930     * @return void 
     931     */ 
    852932    function _sendCmd($cmd) 
    853933    { 
    854934        $status = $this->_sock->getStatus(); 
    855935        if (PEAR::isError($status) || $status['eof']) { 
    856             return new PEAR_Error( 'Failed to write to socket: (connection lost!) ' ); 
    857         } 
    858         if ( PEAR::isError( $error = $this->_sock->write( $cmd . "\r\n" ) ) ) { 
    859             return new PEAR_Error( 'Failed to write to socket: ' . $error->getMessage() ); 
    860         } 
    861  
    862         if( $this->_debug ){ 
    863             // C: means this data was sent by  the client (this class) 
    864             echo "C:$cmd\n"; 
    865         } 
    866         return true; 
    867     } 
    868  
    869     /** 
    870     * Sends a string response to the server 
    871     * 
    872     * @access private 
    873     * @param string $cmd The command to send 
    874     */ 
     936            return PEAR::raiseError('Failed to write to socket: connection lost'); 
     937        } 
     938        if (PEAR::isError($error = $this->_sock->write($cmd . "\r\n"))) { 
     939            return PEAR::raiseError( 
     940                'Failed to write to socket: ' . $error->getMessage() 
     941            ); 
     942        } 
     943        $this->_debug("C: $cmd"); 
     944    } 
     945 
     946    /** 
     947     * Sends a string response to the server. 
     948     * 
     949     * @param string $str The string to send. 
     950     * 
     951     * @return void 
     952     */ 
    875953    function _sendStringResponse($str) 
    876954    { 
    877         $response='{' .  $this->_getLineLength($str) . "+}\r\n" . $str  ; 
    878         return $this->_sendCmd($response); 
    879     } 
    880  
     955        return $this->_sendCmd('{' . $this->_getLineLength($str) . "+}\r\n" . $str); 
     956    } 
     957 
     958    /** 
     959     * Receives a single line from the server. 
     960     * 
     961     * @return string  The server response line. 
     962     */ 
    881963    function _recvLn() 
    882964    { 
    883         $lastline=''; 
    884         if (PEAR::isError( $lastline = $this->_sock->gets( 8192 ) ) ) { 
    885             return new PEAR_Error( 'Failed to write to socket: ' . $lastline->getMessage() ); 
    886         } 
    887         $lastline=rtrim($lastline); 
    888         if($this->_debug){ 
    889             // S: means this data was sent by  the IMAP Server 
    890             echo "S:$lastline\n" ; 
    891         } 
    892  
    893         if( $lastline === '' ) { 
    894             return new PEAR_Error( 'Failed to receive from the socket' ); 
     965        if (PEAR::isError($lastline = $this->_sock->gets(8192))) { 
     966            return PEAR::raiseError( 
     967                'Failed to read from socket: ' . $lastline->getMessage() 
     968            ); 
     969        } 
     970 
     971        $lastline = rtrim($lastline); 
     972        $this->_debug("S: $lastline"); 
     973 
     974        if ($lastline === '') { 
     975            return PEAR::raiseError('Failed to read from socket'); 
    895976        } 
    896977 
     
    899980 
    900981    /** 
    901     * Send a command and retrieves a response from the server. 
    902     * 
    903     * 
    904     * @access private 
    905     * @param string $cmd The command to send 
    906     * @return mixed Reponse string if an OK response, PEAR_Error if a NO response 
    907     */ 
    908     function _doCmd($cmd = '' ) 
    909     { 
    910         $referralCount=0; 
    911         while($referralCount < $this->_maxReferralCount ){ 
    912  
    913             if($cmd != '' ){ 
    914                 if(PEAR::isError($error = $this->_sendCmd($cmd) )) { 
     982     * Send a command and retrieves a response from the server. 
     983     * 
     984     * @param string $cmd   The command to send. 
     985     * @param boolean $auth Whether this is an authentication command. 
     986     * 
     987     * @return string|PEAR_Error  Reponse string if an OK response, PEAR_Error 
     988     *                            if a NO response. 
     989     */ 
     990    function _doCmd($cmd = '', $auth = false) 
     991    { 
     992        $referralCount = 0; 
     993        while ($referralCount < $this->_maxReferralCount) { 
     994            if (strlen($cmd)) { 
     995                if (PEAR::isError($error = $this->_sendCmd($cmd))) { 
    915996                    return $error; 
    916997                } 
    917998            } 
     999 
    9181000            $response = ''; 
    919  
    9201001            while (true) { 
    921                     if(PEAR::isError( $line=$this->_recvLn() )){ 
    922                         return $line; 
     1002                if (PEAR::isError($line = $this->_recvLn())) { 
     1003                    return $line; 
     1004                } 
     1005                $uc_line = $this->_toUpper($line); 
     1006 
     1007                if ('OK' == substr($uc_line, 0, 2)) { 
     1008                    $response .= $line; 
     1009                    return rtrim($response); 
     1010                } 
     1011 
     1012                if ('NO' == substr($uc_line, 0, 2)) { 
     1013                    // Check for string literal error message. 
     1014                    if (preg_match('/^no {([0-9]+)\+?}/i', $line, $matches)) { 
     1015                        $line .= str_replace( 
     1016                            "\r\n", ' ', $this->_sock->read($matches[1] + 2) 
     1017                        ); 
     1018                        $this->_debug("S: $line"); 
    9231019                    } 
    924                     if ('ok' === strtolower(substr($line, 0, 2))) { 
    925                         $response .= $line; 
    926                         return rtrim($response); 
    927  
    928                     } elseif ('no' === strtolower(substr($line, 0, 2))) { 
    929                         // Check for string literal error message 
    930                         if (preg_match('/^no {([0-9]+)\+?}/i', $line, $matches)) { 
    931                             $line .= str_replace("\r\n", ' ', $this->_sock->read($matches[1] + 2 )); 
    932                             if($this->_debug){ 
    933                                 echo "S:$line\n"; 
    934                             } 
     1020                    return PEAR::raiseError(trim($response . substr($line, 2)), 3); 
     1021                } 
     1022 
     1023                if ('BYE' == substr($uc_line, 0, 3)) { 
     1024                    if (PEAR::isError($error = $this->disconnect(false))) { 
     1025                        return PEAR::raiseError( 
     1026                            'Cannot handle BYE, the error was: ' 
     1027                            . $error->getMessage(), 
     1028                            4 
     1029                        ); 
     1030                    } 
     1031                    // Check for referral, then follow it.  Otherwise, carp an 
     1032                    // error. 
     1033                    if (preg_match('/^bye \(referral "(sieve:\/\/)?([^"]+)/i', $line, $matches)) { 
     1034                        // Replace the old host with the referral host 
     1035                        // preserving any protocol prefix. 
     1036                        $this->_data['host'] = preg_replace( 
     1037                            '/\w+(?!(\w|\:\/\/)).*/', $matches[2], 
     1038                            $this->_data['host'] 
     1039                        ); 
     1040                        if (PEAR::isError($error = $this->_handleConnectAndLogin())) { 
     1041                            return PEAR::raiseError( 
     1042                                'Cannot follow referral to ' 
     1043                                . $this->_data['host'] . ', the error was: ' 
     1044                                . $error->getMessage(), 
     1045                                5 
     1046                            ); 
    9351047                        } 
    936                         $msg=trim($response . substr($line, 2)); 
    937                         $code=3; 
    938                         return $this->_raiseError($msg,$code); 
    939                     } elseif ('bye' === strtolower(substr($line, 0, 3))) { 
    940  
    941                         if(PEAR::isError($error = $this->disconnect(false) ) ){ 
    942                             $msg="Can't handle bye, The error was= " . $error->getMessage() ; 
    943                             $code=4; 
    944                             return $this->_raiseError($msg,$code); 
    945                         } 
    946                         //if (preg_match('/^bye \(referral "([^"]+)/i', $line, $matches)) { 
    947                         if (preg_match('/^bye \(referral "(sieve:\/\/)?([^"]+)/i', $line, $matches)) { 
    948                             // Check for referral, then follow it.  Otherwise, carp an error. 
    949                             // Replace the old host with the referral host preserving any protocol prefix 
    950                             $this->_data['host'] = preg_replace('/\w+(?!(\w|\:\/\/)).*/',$matches[2],$this->_data['host']); 
    951                            if (PEAR::isError($error = $this->_handleConnectAndLogin() ) ){ 
    952                                 $msg="Can't follow referral to " . $this->_data['host'] . ", The error was= " . $error->getMessage() ; 
    953                                 $code=5; 
    954                                 return $this->_raiseError($msg,$code); 
    955                             } 
    956                             break; 
    957                             // Retry the command 
    958                             if(PEAR::isError($error = $this->_sendCmd($cmd) )) { 
    959                                 return $error; 
    960                             } 
    961                             continue; 
    962                         } 
    963                         $msg=trim($response . $line); 
    964                         $code=6; 
    965                         return $this->_raiseError($msg,$code); 
    966                     } elseif (preg_match('/^{([0-9]+)\+?}/i', $line, $matches)) { 
    967                         // Matches String Responses. 
    968                         //$line = str_replace("\r\n", ' ', $this->_sock->read($matches[1] + 2 )); 
    969                         $str_size = $matches[1] + 2; 
    970                         $line = ''; 
    971                         $line_length = 0; 
    972                         while ($line_length < $str_size) { 
    973                             $line .= $this->_sock->read($str_size - $line_length); 
    974                             $line_length = $this->_getLineLength($line); 
    975                         } 
    976                         if($this->_debug){ 
    977                             echo "S:$line\n"; 
    978                         } 
    979                         if($this->_state != NET_SIEVE_STATE_AUTHORISATION) { 
    980                             // receive the pending OK only if we aren't authenticating 
    981                             // since string responses during authentication don't need an 
    982                             // OK. 
    983                             $this->_recvLn(); 
    984                         } 
    985                         return $line; 
     1048                        break; 
    9861049                    } 
    987                     $response .= $line . "\r\n"; 
    988                     $referralCount++; 
     1050                    return PEAR::raiseError(trim($response . $line), 6); 
    9891051                } 
    990         } 
    991         $msg="Max referral count reached ($referralCount times) Cyrus murder loop error?"; 
    992         $code=7; 
    993         return $this->_raiseError($msg,$code); 
    994     } 
    995  
    996     /** 
    997     * Sets the debug state 
    998     * 
    999     * @param boolean $debug 
    1000     * @return void 
    1001     */ 
    1002     function setDebug($debug = true) 
    1003     { 
    1004         $this->_debug = $debug; 
    1005     } 
    1006  
    1007     /** 
    1008     * Disconnect from the Sieve server 
    1009     * 
    1010     * @param  string $scriptname The name of the script to be set as active 
    1011     * @return mixed              true on success, PEAR_Error on failure 
    1012     */ 
    1013     function disconnect($sendLogoutCMD=true) 
    1014     { 
    1015         return $this->_cmdLogout($sendLogoutCMD); 
     1052 
     1053                if (preg_match('/^{([0-9]+)\+?}/i', $line, $matches)) { 
     1054                    // Matches String Responses. 
     1055                    $str_size = $matches[1] + 2; 
     1056                    $line = ''; 
     1057                    $line_length = 0; 
     1058                    while ($line_length < $str_size) { 
     1059                        $line .= $this->_sock->read($str_size - $line_length); 
     1060                        $line_length = $this->_getLineLength($line); 
     1061                    } 
     1062                    $this->_debug("S: $line"); 
     1063 
     1064                    if (!$auth) { 
     1065                        // Receive the pending OK only if we aren't 
     1066                        // authenticating since string responses during 
     1067                        // authentication don't need an OK. 
     1068                        $this->_recvLn(); 
     1069                    } 
     1070                    return $line; 
     1071                } 
     1072 
     1073                if ($auth) { 
     1074                    // String responses during authentication don't need an 
     1075                    // OK. 
     1076                    $response .= $line; 
     1077                    return rtrim($response); 
     1078                } 
     1079 
     1080                $response .= $line . "\r\n"; 
     1081                $referralCount++; 
     1082            } 
     1083        } 
     1084 
     1085        return PEAR::raiseError('Max referral count (' . $referralCount . ') reached. Cyrus murder loop error?', 7); 
    10161086    } 
    10171087 
     
    10201090     * has advertised. 
    10211091     * 
    1022      * @param string if !=null,authenticate with this method ($userMethod). 
    1023      * 
    1024      * @return mixed    Returns a string containing the name of the best 
    1025      *                  supported authentication method or a PEAR_Error object 
    1026      *                  if a failure condition is encountered. 
    1027      * @access private 
    1028      * @since  1.0 
     1092     * @param string $userMethod Only consider this method as available. 
     1093     * 
     1094     * @return string  The name of the best supported authentication method or 
     1095     *                 a PEAR_Error object on failure. 
    10291096     */ 
    10301097    function _getBestAuthMethod($userMethod = null) 
    10311098    { 
    1032        if( isset($this->_capability['sasl']) ){ 
    1033            $serverMethods=$this->_capability['sasl']; 
    1034        }else{ 
    1035            // if the server don't send an sasl capability fallback to login auth 
    1036            //return 'LOGIN'; 
    1037            return new PEAR_Error("This server don't support any Auth methods SASL problem?"); 
    1038        } 
    1039  
    1040         if($userMethod != null ){ 
    1041             $methods = array(); 
    1042             $methods[] = $userMethod; 
    1043         }else{ 
    1044  
     1099        if (!isset($this->_capability['sasl'])) { 
     1100            return PEAR::raiseError('This server doesn\'t support any authentication methods. SASL problem?'); 
     1101        } 
     1102 
     1103        $serverMethods = $this->_capability['sasl']; 
     1104 
     1105        if ($userMethod) { 
     1106            $methods = array($userMethod); 
     1107        } else { 
    10451108            $methods = $this->supportedAuthMethods; 
    10461109        } 
    1047         if( ($methods != null) && ($serverMethods != null)){ 
    1048             foreach ( $methods as $method ) { 
    1049                 if ( in_array( $method , $serverMethods ) ) { 
    1050                     return $method; 
    1051                 } 
    1052             } 
    1053             $serverMethods=implode(',' , $serverMethods ); 
    1054             $myMethods=implode(',' ,$this->supportedAuthMethods); 
    1055             return new PEAR_Error("$method NOT supported authentication method!. This server " . 
    1056                 "supports these methods= $serverMethods, but I support $myMethods"); 
    1057         }else{ 
    1058             return new PEAR_Error("This server don't support any Auth methods"); 
    1059         } 
    1060     } 
    1061  
    1062     /** 
    1063     * Return the list of extensions the server supports 
    1064     * 
    1065     * @return mixed              array  on success, PEAR_Error on failure 
    1066     */ 
    1067     function getExtensions() 
    1068     { 
    1069         if (NET_SIEVE_STATE_DISCONNECTED === $this->_state) { 
    1070             $msg='Not currently connected'; 
    1071             $code=7; 
    1072             return $this->_raiseError($msg,$code); 
    1073         } 
    1074  
    1075         return $this->_capability['extensions']; 
    1076     } 
    1077  
    1078     /** 
    1079     * Return true if tyhe server has that extension 
    1080     * 
    1081     * @param string  the extension to compare 
    1082     * @return mixed              array  on success, PEAR_Error on failure 
    1083     */ 
    1084     function hasExtension($extension) 
    1085     { 
    1086         if (NET_SIEVE_STATE_DISCONNECTED === $this->_state) { 
    1087             $msg='Not currently connected'; 
    1088             $code=7; 
    1089             return $this->_raiseError($msg,$code); 
    1090         } 
    1091  
    1092         if(is_array($this->_capability['extensions'] ) ){ 
    1093             foreach( $this->_capability['extensions'] as $ext){ 
    1094                 if( trim( strtolower( $ext ) ) === trim( strtolower( $extension ) ) ) 
    1095                     return true; 
    1096             } 
    1097         } 
    1098         return false; 
    1099     } 
    1100  
    1101     /** 
    1102     * Return the list of auth methods the server supports 
    1103     * 
    1104     * @return mixed              array  on success, PEAR_Error on failure 
    1105     */ 
    1106     function getAuthMechs() 
    1107     { 
    1108         if (NET_SIEVE_STATE_DISCONNECTED === $this->_state) { 
    1109             $msg='Not currently connected'; 
    1110             $code=7; 
    1111             return $this->_raiseError($msg,$code); 
    1112         } 
    1113         if(!isset($this->_capability['sasl']) ){ 
    1114             $this->_capability['sasl']=array(); 
    1115         } 
    1116         return $this->_capability['sasl']; 
    1117     } 
    1118  
    1119     /** 
    1120     * Return true if the server has that extension 
    1121     * 
    1122     * @param string  the extension to compare 
    1123     * @return mixed              array  on success, PEAR_Error on failure 
    1124     */ 
    1125     function hasAuthMech($method) 
    1126     { 
    1127         if (NET_SIEVE_STATE_DISCONNECTED === $this->_state) { 
    1128             $msg='Not currently connected'; 
    1129             $code=7; 
    1130             return $this->_raiseError($msg,$code); 
    1131             //return PEAR::raiseError('Not currently connected'); 
    1132         } 
    1133  
    1134         if(is_array($this->_capability['sasl'] ) ){ 
    1135             foreach( $this->_capability['sasl'] as $ext){ 
    1136                 if( trim( strtolower( $ext ) ) === trim( strtolower( $method ) ) ) 
    1137                     return true; 
    1138             } 
    1139         } 
    1140         return false; 
    1141     } 
    1142  
    1143     /** 
    1144     * Return true if the TLS negotiation was successful 
    1145     * 
    1146     * @access private 
    1147     * @return mixed              true on success, PEAR_Error on failure 
    1148     */ 
     1110 
     1111        if (!$methods || !$serverMethods) { 
     1112            return PEAR::raiseError( 
     1113                'This server doesn\'t support any authentication methods.' 
     1114            ); 
     1115        } 
     1116 
     1117        foreach ($methods as $method) { 
     1118            if (in_array($method, $serverMethods)) { 
     1119                return $method; 
     1120            } 
     1121        } 
     1122 
     1123        return PEAR::raiseError( 
     1124            'No supported authentication method found. The server supports these methods: ' 
     1125            . implode(',', $serverMethods) 
     1126            . ', but we only support: ' 
     1127            . implode(',', $this->supportedAuthMethods) 
     1128        ); 
     1129    } 
     1130 
     1131    /** 
     1132     * Starts a TLS connection. 
     1133     * 
     1134     * @return boolean  True on success, PEAR_Error on failure. 
     1135     */ 
    11491136    function _startTLS() 
    11501137    { 
    1151         if (PEAR::isError($res = $this->_doCmd("STARTTLS"))) { 
     1138        if (PEAR::isError($res = $this->_doCmd('STARTTLS'))) { 
    11521139            return $res; 
    11531140        } 
    11541141 
    1155         if(stream_socket_enable_crypto($this->_sock->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT) == false) { 
    1156             $msg='Failed to establish TLS connection'; 
    1157             $code=2; 
    1158             return $this->_raiseError($msg,$code); 
    1159         } 
    1160  
    1161         if($this->_debug === true) { 
    1162             echo "STARTTLS Negotiation Successful\n"; 
    1163         } 
     1142        if (!stream_socket_enable_crypto($this->_sock->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { 
     1143            return PEAR::raiseError('Failed to establish TLS connection', 2); 
     1144        } 
     1145 
     1146        $this->_debug('STARTTLS negotiation successful'); 
    11641147 
    11651148        // The server should be sending a CAPABILITY response after 
     
    11671150        $this->_doCmd(); 
    11681151 
    1169         // RFC says we need to query the server capabilities again now that 
    1170         // we are under encryption 
    1171         if(PEAR::isError($res = $this->_cmdCapability() )) { 
    1172             $msg='Failed to connect, server said: ' . $res->getMessage(); 
    1173             $code=2; 
    1174             return $this->_raiseError($msg,$code); 
     1152        // RFC says we need to query the server capabilities again now that we 
     1153        // are under encryption. 
     1154        if (PEAR::isError($res = $this->_cmdCapability())) { 
     1155            return PEAR::raiseError( 
     1156                'Failed to connect, server said: ' . $res->getMessage(), 2 
     1157            ); 
    11751158        } 
    11761159 
     
    11781161    } 
    11791162 
    1180     function _getLineLength($string) { 
    1181         if (extension_loaded('mbstring') || @dl(PHP_SHLIB_PREFIX.'mbstring.'.PHP_SHLIB_SUFFIX)) { 
    1182           return mb_strlen($string,'latin1'); 
     1163    /** 
     1164     * Returns the length of a string. 
     1165     * 
     1166     * @param string $string A string. 
     1167     * 
     1168     * @return integer  The length of the string. 
     1169     */ 
     1170    function _getLineLength($string) 
     1171    { 
     1172        if (extension_loaded('mbstring') 
     1173            || @dl(PHP_SHLIB_PREFIX . 'mbstring.' . PHP_SHLIB_SUFFIX) 
     1174        ) { 
     1175            return mb_strlen($string, 'latin1'); 
    11831176        } else { 
    1184           return strlen($string); 
     1177            return strlen($string); 
     1178        } 
     1179    } 
     1180 
     1181    /** 
     1182     * Locale independant strtoupper() implementation. 
     1183     * 
     1184     * @param string $string The string to convert to lowercase. 
     1185     * 
     1186     * @return string  The lowercased string, based on ASCII encoding. 
     1187     */ 
     1188    function _toUpper($string) 
     1189    { 
     1190        $language = setlocale(LC_CTYPE, 0); 
     1191        setlocale(LC_CTYPE, 'C'); 
     1192        $string = strtoupper($string); 
     1193        setlocale(LC_CTYPE, $language); 
     1194        return $string; 
     1195    } 
     1196 
     1197    /** 
     1198     * Write debug text to the current debug output handler. 
     1199     * 
     1200     * @param string $message Debug message text. 
     1201     * 
     1202     * @return void 
     1203     */ 
     1204    function _debug($message) 
     1205    { 
     1206        if ($this->_debug) { 
     1207            if ($this->_debug_handler) { 
     1208                call_user_func_array($this->_debug_handler, array(&$this, $message)); 
     1209            } else { 
     1210                echo "$message\n"; 
     1211            } 
    11851212        } 
    11861213    } 
    11871214} 
    1188 ?> 
  • trunk/roundcubemail/plugins/managesieve/lib/rcube_sieve.php

    r2970 r3085  
    1717define('SIEVE_ERROR_INSTALL', 4);       // script installation 
    1818define('SIEVE_ERROR_ACTIVATE', 5);      // script activation 
     19define('SIEVE_ERROR_DELETE', 6);        // script deletion 
     20define('SIEVE_ERROR_INTERNAL', 7);      // internal error 
    1921define('SIEVE_ERROR_OTHER', 255);       // other/unknown error 
    2022 
     
    2224class rcube_sieve 
    2325{ 
    24   var $sieve;                           // Net_Sieve object 
    25   var $error = false;                   // error flag  
    26   var $list = array();                  // scripts list  
    27  
    28   public $script;                       // rcube_sieve_script object 
    29   private $disabled;                    // array of disabled extensions 
    30  
    31   /** 
     26    private $sieve;                     // Net_Sieve object 
     27    private $error = false;             // error flag  
     28    private $list = array();            // scripts list  
     29 
     30    public $script;                     // rcube_sieve_script object 
     31    public $current;                    // name of currently loaded script 
     32    private $disabled;                  // array of disabled extensions 
     33 
     34    /** 
    3235    * Object constructor 
    3336    * 
     
    3942    * @param  array   Disabled extensions 
    4043    */ 
    41   public function __construct($username, $password='', $host='localhost', $port=2000, $usetls=true, $disabled=array()) 
    42     { 
    43       $this->sieve = new Net_Sieve(); 
    44        
    45 //      $this->sieve->setDebug(); 
    46       if (PEAR::isError($this->sieve->connect($host, $port, NULL, $usetls))) 
    47         return $this->_set_error(SIEVE_ERROR_CONNECTION); 
    48  
    49       if (PEAR::isError($this->sieve->login($username, $password))) 
    50         return $this->_set_error(SIEVE_ERROR_LOGIN); 
    51  
    52       $this->disabled = $disabled; 
    53       $this->_get_script(); 
    54     } 
    55  
    56   /** 
     44    public function __construct($username, $password='', $host='localhost', $port=2000, 
     45                            $usetls=true, $disabled=array(), $debug=false) 
     46    { 
     47        $this->sieve = new Net_Sieve(); 
     48       
     49        if ($debug) 
     50            $this->sieve->setDebug(true, array($this, 'debug_handler')); 
     51       
     52        if (PEAR::isError($this->sieve->connect($host, $port, NULL, $usetls))) 
     53            return $this->_set_error(SIEVE_ERROR_CONNECTION); 
     54 
     55        if (PEAR::isError($this->sieve->login($username, $password))) 
     56            return $this->_set_error(SIEVE_ERROR_LOGIN); 
     57 
     58        $this->disabled = $disabled; 
     59    } 
     60 
     61    /** 
    5762    * Getter for error code 
    5863    */ 
    59   public function error() 
    60     { 
    61       return $this->error ? $this->error : false; 
     64    public function error() 
     65    { 
     66        return $this->error ? $this->error : false; 
    6267    } 
    6368                             
    64   public function save() 
    65     { 
    66       $script = $this->script->as_text(); 
    67  
    68       if (!$script) 
    69         $script = '/* empty script */'; 
    70  
    71       if (PEAR::isError($this->sieve->installScript('roundcube', $script))) 
    72         return $this->_set_error(SIEVE_ERROR_INSTALL); 
    73  
    74       if (PEAR::isError($this->sieve->setActive('roundcube'))) 
    75         return $this->_set_error(SIEVE_ERROR_ACTIVATE); 
    76  
    77       return true; 
    78     } 
    79  
    80   public function get_extensions() 
    81     { 
    82       if ($this->sieve) { 
     69    /** 
     70    * Saves current script into server 
     71    */ 
     72    public function save($name = null) 
     73    { 
     74        if (!$this->sieve) 
     75            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     76         
     77        if (!$this->script) 
     78            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     79         
     80        if (!$name) 
     81            $name = $this->current; 
     82 
     83        $script = $this->script->as_text(); 
     84 
     85        if (!$script) 
     86            $script = '/* empty script */'; 
     87 
     88        if (PEAR::isError($this->sieve->installScript($name, $script))) 
     89            return $this->_set_error(SIEVE_ERROR_INSTALL); 
     90 
     91        return true; 
     92    } 
     93 
     94    /** 
     95    * Saves text script into server 
     96    */ 
     97    public function save_script($name, $content = null) 
     98    { 
     99        if (!$this->sieve) 
     100            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     101         
     102        if (!$content) 
     103            $content = '/* empty script */'; 
     104 
     105        if (PEAR::isError($this->sieve->installScript($name, $content))) 
     106            return $this->_set_error(SIEVE_ERROR_INSTALL); 
     107 
     108        return true; 
     109    } 
     110 
     111    /** 
     112    * Activates specified script 
     113    */ 
     114    public function activate($name = null) 
     115    { 
     116        if (!$this->sieve) 
     117            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     118 
     119        if (!$name) 
     120            $name = $this->current; 
     121 
     122        if (PEAR::isError($this->sieve->setActive($name))) 
     123            return $this->_set_error(SIEVE_ERROR_ACTIVATE); 
     124 
     125        return true; 
     126    } 
     127 
     128    /** 
     129    * Removes specified script 
     130    */ 
     131    public function remove($name = null) 
     132    { 
     133        if (!$this->sieve) 
     134            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     135 
     136        if (!$name) 
     137            $name = $this->current; 
     138 
     139        // script must be deactivated first 
     140        if ($name == $this->sieve->getActive()) 
     141            if (PEAR::isError($this->sieve->setActive(''))) 
     142                return $this->_set_error(SIEVE_ERROR_DELETE); 
     143 
     144        if (PEAR::isError($this->sieve->removeScript($name))) 
     145            return $this->_set_error(SIEVE_ERROR_DELETE); 
     146 
     147        if ($name == $this->current) 
     148            $this->current = null; 
     149 
     150        return true; 
     151    } 
     152 
     153    /** 
     154    * Gets list of supported by server Sieve extensions 
     155    */ 
     156    public function get_extensions() 
     157    { 
     158        if (!$this->sieve) 
     159            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     160         
    83161        $ext = $this->sieve->getExtensions(); 
     162        // we're working on lower-cased names 
     163        $ext = array_map('strtolower', (array) $ext);  
    84164 
    85165        if ($this->script) { 
    86           $supported = $this->script->get_extensions(); 
    87           foreach ($ext as $idx => $ext_name) 
    88             if (!in_array($ext_name, $supported)) 
    89               unset($ext[$idx]); 
    90         } 
    91  
    92         return array_values($ext); 
    93       } 
    94     } 
    95  
    96   private function _get_script() 
    97     { 
    98       if (!$this->sieve) 
     166            $supported = $this->script->get_extensions(); 
     167            foreach ($ext as $idx => $ext_name) 
     168                if (!in_array($ext_name, $supported)) 
     169                    unset($ext[$idx]); 
     170        } 
     171 
     172        return array_values($ext); 
     173    } 
     174 
     175    /** 
     176    * Gets list of scripts from server 
     177    */ 
     178    public function get_scripts() 
     179    { 
     180        if (!$this->list) { 
     181 
     182            if (!$this->sieve) 
     183                return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     184     
     185            $this->list = $this->sieve->listScripts(); 
     186 
     187            if (PEAR::isError($this->list)) 
     188                return $this->_set_error(SIEVE_ERROR_OTHER); 
     189        } 
     190 
     191        return $this->list; 
     192    } 
     193 
     194    /** 
     195    * Returns active script name 
     196    */ 
     197    public function get_active() 
     198    { 
     199        if (!$this->sieve) 
     200            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     201 
     202        return $this->sieve->getActive(); 
     203    } 
     204     
     205    /** 
     206    * Loads script by name 
     207    */ 
     208    public function load($name) 
     209    { 
     210        if (!$this->sieve) 
     211            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     212 
     213        if ($this->current == $name) 
     214            return true; 
     215     
     216        $script = $this->sieve->getScript($name); 
     217     
     218        if (PEAR::isError($script)) 
     219            return $this->_set_error(SIEVE_ERROR_OTHER); 
     220 
     221        // try to parse from Roundcube format 
     222        $this->script = new rcube_sieve_script($script, $this->disabled); 
     223 
     224        // ... else try Squirrelmail format 
     225        if (empty($this->script->content) && $name == 'phpscript') { 
     226 
     227            $script = $this->sieve->getScript('phpscript'); 
     228            $script = $this->_convert_from_squirrel_rules($script); 
     229 
     230            $this->script = new rcube_sieve_script($script, $this->disabled); 
     231        } 
     232 
     233        $this->current = $name; 
     234 
     235        return true; 
     236    } 
     237 
     238    /** 
     239    * Creates empty script or copy of other script 
     240    */ 
     241    public function copy($name, $copy) 
     242    { 
     243        if (!$this->sieve) 
     244            return $this->_set_error(SIEVE_ERROR_INTERNAL); 
     245 
     246        if ($copy) { 
     247            $content = $this->sieve->getScript($copy); 
     248     
     249            if (PEAR::isError($content)) 
     250                return $this->_set_error(SIEVE_ERROR_OTHER); 
     251        } 
     252         
     253        return $this->save_script($name, $content); 
     254    } 
     255 
     256 
     257    private function _convert_from_squirrel_rules($script) 
     258    { 
     259        $i = 0; 
     260        $name = array(); 
     261 
     262        // tokenize rules 
     263        if ($tokens = preg_split('/(#START_SIEVE_RULE.*END_SIEVE_RULE)\n/', $script, -1, PREG_SPLIT_DELIM_CAPTURE)) 
     264            foreach($tokens as $token) { 
     265                if (preg_match('/^#START_SIEVE_RULE.*/', $token, $matches)) { 
     266                    $name[$i] = "unnamed rule ".($i+1); 
     267                    $content .= "# rule:[".$name[$i]."]\n"; 
     268                } 
     269                elseif (isset($name[$i])) { 
     270                    $content .= "if $token\n"; 
     271                    $i++; 
     272                } 
     273            } 
     274 
     275        return $content; 
     276    } 
     277 
     278    private function _set_error($error) 
     279    { 
     280        $this->error = $error; 
    99281        return false; 
    100      
    101       $this->list = $this->sieve->listScripts(); 
    102  
    103       if (PEAR::isError($this->list)) 
    104         return $this->_set_error(SIEVE_ERROR_OTHER); 
    105      
    106       if (in_array('roundcube', $this->list)) 
    107         { 
    108           $script = $this->sieve->getScript('roundcube'); 
    109      
    110           if (PEAR::isError($script)) 
    111             return $this->_set_error(SIEVE_ERROR_OTHER); 
    112         } 
    113       // import scripts from squirrelmail 
    114       elseif (in_array('phpscript', $this->list)) 
    115         { 
    116           $script = $this->sieve->getScript('phpscript'); 
    117  
    118           $script = $this->_convert_from_squirrel_rules($script); 
    119  
    120           $this->script = new rcube_sieve_script($script, $this->disabled); 
    121         
    122           $this->save(); 
    123  
    124           $script = $this->sieve->getScript('roundcube'); 
    125  
    126           if (PEAR::isError($script)) 
    127             return $this->_set_error(SIEVE_ERROR_OTHER); 
    128         } 
    129       else 
    130         { 
    131           $this->_set_error(SIEVE_ERROR_NOT_EXISTS); 
    132           $script = ''; 
    133         } 
    134  
    135       $this->script = new rcube_sieve_script($script, $this->disabled); 
    136     } 
    137      
    138   private function _convert_from_squirrel_rules($script) 
    139     { 
    140       $i = 0; 
    141       $name = array(); 
    142       // tokenize rules 
    143       if ($tokens = preg_split('/(#START_SIEVE_RULE.*END_SIEVE_RULE)\n/', $script, -1, PREG_SPLIT_DELIM_CAPTURE)) 
    144         foreach($tokens as $token) 
    145           { 
    146             if (preg_match('/^#START_SIEVE_RULE.*/', $token, $matches)) 
    147               { 
    148                 $name[$i] = "unnamed rule ".($i+1); 
    149                 $content .= "# rule:[".$name[$i]."]\n"; 
    150               } 
    151             elseif (isset($name[$i])) 
    152               { 
    153                 $content .= "if ".$token."\n"; 
    154                 $i++; 
    155               } 
    156           } 
    157  
    158       return $content; 
    159     } 
    160  
    161  
    162   private function _set_error($error) 
    163     { 
    164       $this->error = $error; 
    165       return false; 
    166     }     
     282    } 
     283 
     284    /** 
     285    * This is our own debug handler for connection 
     286    * @access public 
     287    */ 
     288    public function debug_handler(&$sieve, $message) 
     289    { 
     290        write_log('sieve', preg_replace('/\r\n$/', '', $message)); 
     291    }                    
    167292} 
    168293 
    169294class rcube_sieve_script 
    170295{ 
    171   var $content = array();       // script rules array    
     296  public $content = array();    // script rules array    
    172297 
    173298  private $supported = array(   // extensions supported by class 
  • trunk/roundcubemail/plugins/managesieve/localization/bg_BG.inc

    r2510 r3085  
    4343$messages['filterdeleteerror'] = 'НевъзЌПжМПст за ОзтрОваМе Ма фОлтър. Сървър грешка'; 
    4444$messages['filterdeleted'] = 'ЀОлтърът е ОзтрОт успешМП'; 
    45 $messages['filterconfirmdelete'] = 'НаОстОМа лО Оскате Ўа ОзтрОете ОзбраМОя фОлтър?'; 
     45$messages['filterdeleteconfirm'] = 'НаОстОМа лО Оскате Ўа ОзтрОете ОзбраМОя фОлтър?'; 
    4646$messages['filtersaved'] = 'ЀОлтърът е запОсаМ успешМП'; 
    4747$messages['filtersaveerror'] = 'ЀОлтърът Ме ЌПже Ўа бъЎе запОсаМ. Сървър грешка.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/cs_CZ.inc

    r3000 r3085  
    5151$messages['filterdeleteerror'] = 'Nebylo moÅŸné smazat filtr. Server nahlásil chybu'; 
    5252$messages['filterdeleted'] = 'Filtr byl smazán'; 
    53 $messages['filterconfirmdelete'] = 'Opravdu chcete smazat vybranÜ filtr?'; 
     53$messages['filterdeleteconfirm'] = 'Opravdu chcete smazat vybranÜ filtr?'; 
    5454$messages['filtersaved'] = 'Filtr byl uloÅŸen'; 
    5555$messages['filtersaveerror'] = 'Nebylo moÅŸné uloÅŸit filtr. Server nahlásil chybu.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/de_CH.inc

    r2539 r3085  
    4242$messages['filterdeleteerror'] = 'Fehler beim des löschen  Filters. Serverfehler'; 
    4343$messages['filterdeleted'] = 'Filter erfolgreich gelöscht'; 
    44 $messages['filterconfirmdelete'] = 'Möchten Sie den Filter löschen ?'; 
     44$messages['filterdeleteconfirm'] = 'Möchten Sie den Filter löschen ?'; 
    4545$messages['filtersaved'] = 'Filter gespeichert'; 
    4646$messages['filtersaveerror'] = 'Serverfehler, konnte den Filter nicht speichern.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/de_DE.inc

    r2964 r3085  
    4343$messages['filterdeleteerror'] = 'Fehler beim Löschen des Filters. Serverfehler'; 
    4444$messages['filterdeleted'] = 'Filter erfolgreich gelöscht'; 
    45 $messages['filterconfirmdelete'] = 'Möchten Sie den Filter löschen?'; 
     45$messages['filterdeleteconfirm'] = 'Möchten Sie den Filter löschen?'; 
    4646$messages['filtersaved'] = 'Filter gespeichert'; 
    4747$messages['filtersaveerror'] = 'Serverfehler, konnte den Filter nicht speichern.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/en_GB.inc

    r3031 r3085  
    4343$messages['filterdeleteerror'] = 'Unable to delete filter. Server error occured'; 
    4444$messages['filterdeleted'] = 'Filter deleted successfully'; 
    45 $messages['filterconfirmdelete'] = 'Do you really want to delete selected filter?'; 
     45$messages['filterdeleteconfirm'] = 'Do you really want to delete selected filter?'; 
    4646$messages['filtersaved'] = 'Filter saved successfully'; 
    4747$messages['filtersaveerror'] = 'Unable to save filter. Server error occured.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/en_US.inc

    r2510 r3085  
    3737$labels['vacationreason'] = 'Message body (vacation reason):'; 
    3838$labels['rulestop'] = 'Stop evaluating rules'; 
     39$labels['filterset'] = 'Filters set'; 
     40$labels['filtersetadd'] = 'Add filters set'; 
     41$labels['filtersetdel'] = 'Delete current filters set'; 
     42$labels['filtersetact'] = 'Activate current filters set'; 
     43$labels['filterdef'] = 'Filter definition'; 
     44$labels['filtersetname'] = 'Filters set name'; 
     45$labels['newfilterset'] = 'New filters set'; 
     46$labels['active'] = 'active'; 
     47$labels['copyfromset'] = 'Copy filters from set'; 
     48$labels['none'] = '- none -'; 
    3949 
    4050$messages = array(); 
     
    4353$messages['filterdeleteerror'] = 'Unable to delete filter. Server error occured'; 
    4454$messages['filterdeleted'] = 'Filter deleted successfully'; 
    45 $messages['filterconfirmdelete'] = 'Do you really want to delete selected filter?'; 
    4655$messages['filtersaved'] = 'Filter saved successfully'; 
    47 $messages['filtersaveerror'] = 'Unable to save filter. Server error occured.'; 
     56$messages['filtersaveerror'] = 'Unable to save filter. Server error occured'; 
     57$messages['filterdeleteconfirm'] = 'Do you really want to delete selected filter?'; 
    4858$messages['ruledeleteconfirm'] = 'Are you sure, you want to delete selected rule?'; 
    4959$messages['actiondeleteconfirm'] = 'Are you sure, you want to delete selected action?'; 
    5060$messages['forbiddenchars'] = 'Forbidden characters in field'; 
    5161$messages['cannotbeempty'] = 'Field cannot be empty'; 
     62$messages['setactivateerror'] = 'Unable to activate selected filters set. Server error occured'; 
     63$messages['setdeleteerror'] = 'Unable to delete selected filters set. Server error occured'; 
     64$messages['setactivated'] = 'Filters set activated successfully'; 
     65$messages['setdeleted'] = 'Filters set deleted successfully'; 
     66$messages['setdeleteconfirm'] = 'Are you sure, you want to delete selected filters set?'; 
     67$messages['setcreateerror'] = 'Unable to create filters set. Server error occured'; 
     68$messages['setcreated'] = 'Filters set created successfully'; 
     69$messages['emptyname'] = 'Unable to create filters set. Empty set name'; 
     70$messages['nametoolong'] = 'Unable to create filters set. Name too long' 
    5271 
    5372?> 
  • trunk/roundcubemail/plugins/managesieve/localization/es_ES.inc

    r2865 r3085  
    4444$messages['filterdeleteerror'] = 'Imposible borrar filtro. Ha ocurrido un error en el servidor'; 
    4545$messages['filterdeleted'] = 'Filtro borrado satisfactoriamente'; 
    46 $messages['filterconfirmdelete'] = '¿Realmente desea borrar el filtro seleccionado?'; 
     46$messages['filterdeleteconfirm'] = '¿Realmente desea borrar el filtro seleccionado?'; 
    4747$messages['filtersaved'] = 'Filtro guardado satisfactoriamente'; 
    4848$messages['filtersaveerror'] = 'Imposible guardar ell filtro. Ha ocurrido un error en el servidor'; 
  • trunk/roundcubemail/plugins/managesieve/localization/et_EE.inc

    r2827 r3085  
    4343$messages['filterdeleteerror'] = 'Filtri kustutamine nurjus. Ilmnes serveri tõrge.'; 
    4444$messages['filterdeleted'] = 'Filter edukalt kustutatud'; 
    45 $messages['filterconfirmdelete'] = 'Soovid valitud filtri kustutada?'; 
     45$messages['filterdeleteconfirm'] = 'Soovid valitud filtri kustutada?'; 
    4646$messages['filtersaved'] = 'Filter edukalt salvestatud'; 
    4747$messages['filtersaveerror'] = 'Filtri salvestamine nurjus. Ilmnes serveri tõrge.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/fi_FI.inc

    r2510 r3085  
    3939$messages['filterdeleteerror'] = 'Suodattimen poistaminen epÀonnistui. Palvelin virhe'; 
    4040$messages['filterdeleted'] = 'Suodatin poistettu'; 
    41 $messages['filterconfirmdelete'] = 'Haluatko varmasti poistaa valitut suodattimet?'; 
     41$messages['filterdeleteconfirm'] = 'Haluatko varmasti poistaa valitut suodattimet?'; 
    4242$messages['filtersaved'] = 'Suodatin tallennettu'; 
    4343$messages['filtersaveerror'] = 'Suodattimen tallennus epÀonnistui. Palvelin virhe'; 
  • trunk/roundcubemail/plugins/managesieve/localization/fr_FR.inc

    r2510 r3085  
    4343$messages['filterdeleteerror'] = 'Suppression du filtre impossible. Le serveur à produit une erreur'; 
    4444$messages['filterdeleted'] = 'Le filtre a bien été supprimé'; 
    45 $messages['filterconfirmdelete'] = 'Voulez-vous vraiment supprimer le filtre sélectionné?'; 
     45$messages['filterdeleteconfirm'] = 'Voulez-vous vraiment supprimer le filtre sélectionné?'; 
    4646$messages['filtersaved'] = 'Le filtre a bien été enregistré'; 
    4747$messages['filtersaveerror'] = 'Enregistrement du filtre impossibe. Le serveur à produit une erreur'; 
  • trunk/roundcubemail/plugins/managesieve/localization/hu_HU.inc

    r2510 r3085  
    4444$messages['filterdeleteerror'] = 'A szűrőt nem lehet törölni, szerverhiba történt'; 
    4545$messages['filterdeleted'] = 'A szűrő törlése sikeres'; 
    46 $messages['filterconfirmdelete'] = 'Biztosan törli ezt a szűrőt?'; 
     46$messages['filterdeleteconfirm'] = 'Biztosan törli ezt a szűrőt?'; 
    4747$messages['filtersaved'] = 'A szűrő mentése sikeres'; 
    4848$messages['filtersaveerror'] = 'A szűrő mentése sikertelen, szerverhiba történt'; 
  • trunk/roundcubemail/plugins/managesieve/localization/it_IT.inc

    r2641 r3085  
    4444$messages['filterdeleteerror'] = 'Eliminazione del filtro fallita. Si Ú verificato un errore nel server'; 
    4545$messages['filterdeleted'] = 'Filtro eliminato con successo'; 
    46 $messages['filterconfirmdelete'] = 'Vuoi veramente eliminare il filtro selezionato?'; 
     46$messages['filterdeleteconfirm'] = 'Vuoi veramente eliminare il filtro selezionato?'; 
    4747$messages['filtersaved'] = 'Filtro salvato con successo'; 
    4848$messages['filtersaveerror'] = 'Salvataggio del filtro fallito. Si Ú verificato un errore nel server'; 
  • trunk/roundcubemail/plugins/managesieve/localization/nl_NL.inc

    r2886 r3085  
    3939$messages['filterdeleteerror'] = 'Kan filter niet verwijderen. Er is een fout opgetreden'; 
    4040$messages['filterdeleted'] = 'Filter succesvol verwijderd'; 
    41 $messages['filterconfirmdelete'] = 'Weet je zeker dat je het geselecteerde filter wilt verwijderen?'; 
     41$messages['filterdeleteconfirm'] = 'Weet je zeker dat je het geselecteerde filter wilt verwijderen?'; 
    4242$messages['filtersaved'] = 'Filter succesvol opgeslagen'; 
    4343$messages['filtersaveerror'] = 'Kan filter niet opslaan. Er is een fout opgetreden.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/pl_PL.inc

    r2641 r3085  
    4545$labels['vacationaddresses'] = 'Lista dodatkowych adresów odbiorców (oddzielonych przecinkami):'; 
    4646$labels['vacationreason'] = 'Treść (przyczyna nieobecności):'; 
     47$labels['filterset'] = 'Zbiór filtrów'; 
     48$labels['filtersetadd'] = 'Dodaj zbiór filtrów'; 
     49$labels['filtersetdel'] = 'Usuń bierzÄ 
     50cy zbiór filtrów'; 
     51$labels['filtersetact'] = 'Aktywuj bierzÄ 
     52cy zbiór filtrów'; 
     53$labels['filterdef'] = 'Definicja filtra'; 
     54$labels['filtersetname'] = 'Nazwa zbioru filtrów'; 
     55$labels['newfilterset'] = 'Nowy zbiór filtrów'; 
     56$labels['active'] = 'aktywny'; 
     57$labels['copyfromset'] = 'Skopiuj filtry ze zbioru'; 
     58$labels['none'] = '- brak -'; 
    4759 
    4860$messages = array(); 
     
    5769d serwera'; 
    5870$messages['filterdeleted'] = 'Filtr został usunięty pomyślnie'; 
    59 $messages['filterconfirmdelete'] = 'Czy na pewno chcesz usunÄ 
     71$messages['filterdeleteconfirm'] = 'Czy na pewno chcesz usunÄ 
    6072ć wybrany filtr?'; 
    6173$messages['filtersaved'] = 'Filtr został zapisany pomyślnie'; 
     
    7183$messages['forbiddenchars'] = 'Pole zawiera niedozwolone znaki'; 
    7284$messages['cannotbeempty'] = 'Pole nie moÅŒe być puste'; 
     85$messages['setactivateerror'] = 'Nie moÅŒna aktywować wybranego zbioru filtrów. BłĠ
     86d serwera'; 
     87$messages['setdeleteerror'] = 'Nie moÅŒna usunÄ 
     88ć wybranego zbioru filtrów. BłĠ
     89d serwera'; 
     90$messages['setactivated'] = 'Zbiór filtrów został aktywowany pomyślnie'; 
     91$messages['setdeleted'] = 'Zbiór filtrów został usunięty pomyślnie'; 
     92$messages['setdeleteconfirm'] = 'Czy na pewno chcesz usunÄ 
     93ć wybrany zbiór filtrów?'; 
     94$messages['setcreateerror'] = 'Nie moÅŒna utworzyć zbioru filtrów. BłĠ
     95d serwera'; 
     96$messages['setcreated'] = 'Zbiór filtrów został utworzony pomyślnie'; 
     97$messages['emptyname'] = 'Nie moÅŒna utworzyć zbioru filtrów. Pusta nazwa zbioru'; 
     98$messages['nametoolong'] = 'Nie moÅŒna utworzyć zbioru filtrów. Nazwa zbyt długa' 
    7399 
    74100?> 
  • trunk/roundcubemail/plugins/managesieve/localization/pt_BR.inc

    r2715 r3085  
    4343$messages['filterdeleteerror'] = 'Não foi possível excluir filtro. Occorreu um erro de servidor'; 
    4444$messages['filterdeleted'] = 'Filtro excluído com sucesso'; 
    45 $messages['filterconfirmdelete'] = 'Deseja realmente excluir o filtro selecionado?'; 
     45$messages['filterdeleteconfirm'] = 'Deseja realmente excluir o filtro selecionado?'; 
    4646$messages['filtersaved'] = 'Filtro gravado com sucesso'; 
    4747$messages['filtersaveerror'] = 'Não foi possível gravar filtro. Occoreu um erro de servidor.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/ru_RU.inc

    r3028 r3085  
    3737$labels['sender'] = 'ОтправОтель'; 
    3838$labels['recipient'] = 'ППлучатель'; 
    39 $labels['vacationaddresses'] = 'СпОсПк ЎПпПлМОтельМыѠ
    40  Ð°ÐŽÑ€ÐµÑÐŸÐ² пПчты (разЎелёММый запятыЌО):'; 
    41 $labels['vacationdays'] = 'Как частП Птправлять сППбщеМОе (раз в скПлькП ЎМей):'; 
    42 $labels['vacationreason'] = 'Текст сППбщеМОя (прОчОМы ПтсутствОя):'; 
    43 $labels['rulestop'] = 'Не Пбрабатывать пПслеЎующОе правОла'; 
    4439 
    4540$messages = array(); 
     
    4843$messages['filterdeleteerror'] = 'НевПзЌПжМП уЎалОть фОльтр. ОшОбка сервера'; 
    4944$messages['filterdeleted'] = 'ЀОльтр успешМП уЎалёМ'; 
    50 $messages['filterconfirmdelete'] = 'Вы ЎействОтельМП Ñ 
     45$messages['filterdeleteconfirm'] = 'Вы ЎействОтельМП Ñ 
    5146ПтОте уЎалОть фОльтр?'; 
    5247$messages['filtersaved'] = 'ЀОльтр успешМП сПѠ
  • trunk/roundcubemail/plugins/managesieve/localization/sl_SI.inc

    r2864 r3085  
    4343$messages['filterdeleteerror'] = 'Pravila ni bilo mogoče izbrisati. PriÅ¡lo je do napake.'; 
    4444$messages['filterdeleted'] = 'Pravilo je bilo uspeÅ¡no izbrisano.'; 
    45 $messages['filterconfirmdelete'] = 'Ste prepričani, da ÅŸelite izbrisati izbrano pravilo?'; 
     45$messages['filterdeleteconfirm'] = 'Ste prepričani, da ÅŸelite izbrisati izbrano pravilo?'; 
    4646$messages['filtersaved'] = 'Pravilo je bilo uspeÅ¡no shranjeno'; 
    4747$messages['filtersaveerror'] = 'Pravilo ni bilo shranjeno. PriÅ¡lo je do napake.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/sv_SE.inc

    r2510 r3085  
    4444$messages['filterdeleteerror'] = 'Filtret kunde inte tas bort pÃ¥ grund av serverfel'; 
    4545$messages['filterdeleted'] = 'Filtret Àr borttaget'; 
    46 $messages['filterconfirmdelete'] = 'Vill du ta bort det markerade filtret?'; 
     46$messages['filterdeleteconfirm'] = 'Vill du ta bort det markerade filtret?'; 
    4747$messages['filtersaved'] = 'Filtret har sparats'; 
    4848$messages['filtersaveerror'] = 'Filtret kunde inte sparas pÃ¥ grund av serverfel'; 
  • trunk/roundcubemail/plugins/managesieve/localization/uk_UA.inc

    r2812 r3085  
    4949$messages['filterdeleteerror'] = 'НеЌПжлОвП вОЎалОтО фільтр. ППЌОлка сервера.'; 
    5050$messages['filterdeleted'] = 'Ѐільтр успішМП вОЎалеМП.'; 
    51 $messages['filterconfirmdelete'] = 'ВО ЎійсМП Ñ 
     51$messages['filterdeleteconfirm'] = 'ВО ЎійсМП Ñ 
    5252Пчете вОЎалОтО вОбраМОй фільтр?'; 
    5353$messages['filtersaved'] = 'Ѐільтр успішМП збережеМП.'; 
  • trunk/roundcubemail/plugins/managesieve/localization/zh_CN.inc

    r2510 r3085  
    4343$messages['filterdeleteerror'] = '无法删陀过滀噚。服务噚错误'; 
    4444$messages['filterdeleted'] = '过滀噚已成功删陀'; 
    45 $messages['filterconfirmdelete'] = '悚确定芁删陀所选择的过滀噚吗'; 
     45$messages['filterdeleteconfirm'] = '悚确定芁删陀所选择的过滀噚吗'; 
    4646$messages['filtersaved'] = '过滀噚已成功保存。'; 
    4747$messages['filtersaveerror'] = '无法保存过滀噚。服务噚错误'; 
  • trunk/roundcubemail/plugins/managesieve/managesieve.js

    r2761 r3085  
    2020    rcmail.register_command('plugin.managesieve-up', function() { rcmail.managesieve_up() }, true); 
    2121    rcmail.register_command('plugin.managesieve-down', function() { rcmail.managesieve_down() }, true); 
     22    rcmail.register_command('plugin.managesieve-set', function() { rcmail.managesieve_set() }, true); 
     23    rcmail.register_command('plugin.managesieve-setadd', function() { rcmail.managesieve_setadd() }, true); 
     24    rcmail.register_command('plugin.managesieve-setdel', function() { rcmail.managesieve_setdel() }, true); 
     25    rcmail.register_command('plugin.managesieve-setact', function() { rcmail.managesieve_setact() }, true); 
    2226 
    2327    if (rcmail.env.action == 'plugin.managesieve') 
     
    2630          rcmail.enable_command('plugin.managesieve-save', true); 
    2731        else { 
    28           rcmail.enable_command('plugin.managesieve-del', 'plugin.managesieve-up', 'plugin.managesieve-down', false); 
    29           rcmail.enable_command('plugin.managesieve-add', !rcmail.env.sieveconnerror); 
    30         } 
    31          
     32          rcmail.enable_command('plugin.managesieve-del', 'plugin.managesieve-up', 
     33            'plugin.managesieve-down', false); 
     34          rcmail.enable_command('plugin.managesieve-add', 'plugin.managesieve-setadd', !rcmail.env.sieveconnerror); 
     35          rcmail.enable_command('plugin.managesieve-set', rcmail.gui_objects.filtersetslist != null); 
     36          rcmail.enable_command('plugin.managesieve-setact', 
     37            (rcmail.gui_objects.filtersetslist && rcmail.gui_objects.filtersetslist.value != rcmail.env.active_set)); 
     38          rcmail.enable_command('plugin.managesieve-setdel', 
     39            (rcmail.gui_objects.filtersetslist && rcmail.gui_objects.filtersetslist.length > 1)); 
     40        } 
    3241        if (rcmail.gui_objects.filterslist) { 
    3342            var p = rcmail; 
     
    5463    var id = this.filters_list.get_single_selection(); 
    5564 
    56     if (confirm(this.get_label('managesieve.filterconfirmdelete'))) 
     65    if (confirm(this.get_label('managesieve.filterdeleteconfirm'))) 
    5766      this.http_request('plugin.managesieve', 
    5867            '_act=delete&_fid='+this.filters_list.rows[id].uid, true); 
     
    204213  rcube_webmail.prototype.managesieve_save = function() 
    205214    { 
    206       if (parent.rcmail && parent.rcmail.filters_list) 
     215      if (parent.rcmail && parent.rcmail.filters_list && this.gui_objects.sieveform.name != 'filtersetform') 
    207216        { 
    208217        var id = parent.rcmail.filters_list.get_single_selection(); 
     
    379388        } 
    380389    } 
     390 
     391  // Set change 
     392  rcube_webmail.prototype.managesieve_set = function() 
     393    { 
     394    var script = $(this.gui_objects.filtersetslist).val(); 
     395    location.href = this.env.comm_path+'&_action=plugin.managesieve&_sid='+script; 
     396    }; 
     397 
     398  // Set activate 
     399  rcube_webmail.prototype.managesieve_setact = function() 
     400    { 
     401      if (!this.gui_objects.filtersetslist) 
     402        return false; 
     403 
     404      var script = this.gui_objects.filtersetslist.value; 
     405      this.http_post('plugin.managesieve', '_act=setact&_set='+script); 
     406    }; 
     407 
     408  // Set activate flag in sets list after set activation 
     409  rcube_webmail.prototype.managesieve_reset = function(name) 
     410    { 
     411      if (!this.gui_objects.filtersetslist || !name) 
     412        return false; 
     413 
     414      var opts = this.gui_objects.filtersetslist.getElementsByTagName('option'); 
     415      var regx = new RegExp(RegExp.escape(' (' + this.get_label('managesieve.active') + ')')); 
     416       
     417      for (var x=1; x<opts.length; x++) 
     418        if (opts[x].value != name && opts[x].innerHTML.match(regx)) 
     419          opts[x].innerHTML = opts[x].innerHTML.replace(regx, ''); 
     420        else if (opts[x].value == name) 
     421          opts[x].innerHTML = opts[x].innerHTML + ' (' + this.get_label('managesieve.active') + ')'; 
     422    }; 
     423 
     424  // Set delete 
     425  rcube_webmail.prototype.managesieve_setdel = function() 
     426    { 
     427      if (!this.gui_objects.filtersetslist) 
     428        return false; 
     429 
     430      if (!confirm(this.get_label('managesieve.setdeleteconfirm'))) 
     431        return false; 
     432 
     433      var script = this.gui_objects.filtersetslist.value; 
     434      this.http_post('plugin.managesieve', '_act=setdel&_set='+script); 
     435    }; 
     436 
     437  // Set add 
     438  rcube_webmail.prototype.managesieve_setadd = function() 
     439    { 
     440      this.filters_list.clear_selection(); 
     441      this.enable_command('plugin.managesieve-up', 'plugin.managesieve-down', 'plugin.managesieve-del', false); 
     442 
     443      if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) 
     444        { 
     445        target = window.frames[this.env.contentframe]; 
     446        this.set_busy(true, 'loading'); 
     447        target.location.href = this.env.comm_path+'&_action=plugin.managesieve&_framed=1&_newset=1'; 
     448        } 
     449    }; 
     450 
     451 
     452  rcube_webmail.prototype.managesieve_reload = function(set) 
     453    { 
     454      this.env.reload_set = set; 
     455      window.setTimeout(function() { 
     456        location.href = rcmail.env.comm_path + '&_action=plugin.managesieve' 
     457          + (rcmail.env.reload_set ? '&_sid=' + rcmail.env.reload_set : '') 
     458        }, 500); 
     459    }; 
     460 
    381461} 
  • trunk/roundcubemail/plugins/managesieve/managesieve.php

    r3042 r3085  
    88 * with server using managesieve protocol. Adds Filters tab in Settings. 
    99 * 
    10  * @version 1.7 
     10 * @version 2.0 
    1111 * @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl> 
    1212 * 
     
    3636 
    3737    // register actions 
    38     $this->register_action('plugin.managesieve', array($this, 'managesieve_init')); 
     38    $this->register_action('plugin.managesieve', array($this, 'managesieve_actions')); 
    3939    $this->register_action('plugin.managesieve-save', array($this, 'managesieve_save')); 
    4040 
     
    5353    $this->rc->output->add_handlers(array( 
    5454        'filterslist' => array($this, 'filters_list'), 
     55        'filtersetslist' => array($this, 'filtersets_list'), 
    5556        'filterframe' => array($this, 'filter_frame'), 
    5657        'filterform' => array($this, 'filter_form'), 
     58        'filtersetform' => array($this, 'filterset_form'), 
    5759    )); 
    5860 
     
    6668        $this->rc->config->get('managesieve_port', 2000), 
    6769        $this->rc->config->get('managesieve_usetls', false), 
    68         $this->rc->config->get('managesieve_disabled_extensions')); 
    69  
    70     $error = $this->sieve->error(); 
    71  
    72     if ($error == SIEVE_ERROR_NOT_EXISTS) 
     70        $this->rc->config->get('managesieve_disabled_extensions'), 
     71        $this->rc->config->get('managesieve_debug', false) 
     72    ); 
     73 
     74    if (!($error = $this->sieve->error())) { 
     75       
     76      $list = $this->sieve->get_scripts(); 
     77      $active = $this->sieve->get_active(); 
     78      $_SESSION['managesieve_active'] = $active; 
     79       
     80      if (!empty($_GET['_sid'])) { 
     81        $script_name = get_input_value('_sid', RCUBE_INPUT_GET); 
     82      } else if (!empty($_SESSION['managesieve_current'])) { 
     83        $script_name = $_SESSION['managesieve_current']; 
     84      } else { 
     85        // get active script 
     86        if ($active) { 
     87          $script_name = $active; 
     88        } else if ($list) { 
     89          $script_name = $list[0]; 
     90        // create a new (initial) script 
     91        } else { 
     92          // if script not exists build default script contents 
     93          $script_file = $this->rc->config->get('managesieve_default'); 
     94          $script_name = 'roundcube'; 
     95          if ($script_file && is_readable($script_file)) 
     96            $content = file_get_contents($script_file); 
     97 
     98          // add script and set it active     
     99          if ($this->sieve->save_script($script_name, $content))  
     100            if ($this->sieve->activate($script_name)) 
     101              $_SESSION['managesieve_active'] = $script_name; 
     102        } 
     103      } 
     104 
     105      if ($script_name) 
     106        $this->sieve->load($script_name); 
     107 
     108      $error = $this->sieve->error(); 
     109    } 
     110     
     111    // finally set script objects 
     112    if ($error) 
    73113    { 
    74       // if script not exists build default script contents 
    75       $script_file = $this->rc->config->get('managesieve_default'); 
    76       if ($script_file && is_readable($script_file)) 
    77         $this->sieve->script->add_text(file_get_contents($script_file));  
    78       // that's not exactly an error 
    79       $error = false; 
    80     } 
    81     elseif ($error) 
    82     { 
    83       switch ($error) 
    84       { 
     114      switch ($error) { 
    85115        case SIEVE_ERROR_CONNECTION: 
    86116        case SIEVE_ERROR_LOGIN: 
     
    91121        break; 
    92122      } 
    93  
    94123      // to disable 'Add filter' button set env variable 
    95124      $this->rc->output->set_env('filterconnerror', true); 
    96     } 
    97  
    98     // finally set script objects 
    99     if ($error) 
    100     { 
    101125      $this->script = array(); 
    102126    } 
     
    105129      $this->script = $this->sieve->script->as_array(); 
    106130      $this->exts = $this->sieve->get_extensions(); 
     131      $this->rc->output->set_env('active_set', $_SESSION['managesieve_active']); 
     132      $_SESSION['managesieve_current'] = $this->sieve->current; 
    107133    } 
    108134     
     
    110136  } 
    111137 
    112   function managesieve_init() 
     138  function managesieve_actions() 
    113139  { 
    114140    // Init plugin and handle managesieve connection 
     
    135161        } 
    136162      } 
    137       elseif ($action=='down' && !$error) 
     163      else if ($action=='down' && !$error) 
    138164      { 
    139165        if (isset($this->script[$fid]) && isset($this->script[$fid+1])) 
     
    143169            $result = $this->sieve->save(); 
    144170       
    145           if ($result) { 
     171          if ($result === true) { 
    146172//          $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); 
    147173            $this->rc->output->command('managesieve_updatelist', 'down', '', $fid); 
    148           } else 
     174          } else { 
    149175            $this->rc->output->show_message('managesieve.filtersaveerror', 'error'); 
    150         } 
    151       } 
    152       elseif ($action=='delete' && !$error) 
     176          } 
     177        } 
     178      } 
     179      else if ($action=='delete' && !$error) 
    153180      { 
    154181        if (isset($this->script[$fid])) 
     
    157184            $result = $this->sieve->save(); 
    158185 
    159           if (!$result) 
    160             $this->rc->output->show_message('managesieve.filterdeleteerror', 'error'); 
    161           else { 
     186          if ($result === true) { 
    162187            $this->rc->output->show_message('managesieve.filterdeleted', 'confirmation'); 
    163188            $this->rc->output->command('managesieve_updatelist', 'delete', '', $fid); 
     189          } else { 
     190            $this->rc->output->show_message('managesieve.filterdeleteerror', 'error'); 
    164191          } 
    165         } 
     192        } 
     193      } 
     194      else if ($action=='setact' && !$error) 
     195      { 
     196        $script_name = get_input_value('_set', RCUBE_INPUT_GPC); 
     197        $result = $this->sieve->activate($script_name); 
     198         
     199        if ($result === true) { 
     200          $this->rc->output->set_env('active_set', $script_name); 
     201          $this->rc->output->show_message('managesieve.setactivated', 'confirmation'); 
     202          $this->rc->output->command('enable_command', 'plugin.managesieve-setact', false); 
     203          $this->rc->output->command('managesieve_reset', $script_name); 
     204          $_SESSION['managesieve_active'] = $script_name; 
     205        } else { 
     206          $this->rc->output->show_message('managesieve.setactivateerror', 'error'); 
     207        } 
     208      } 
     209      else if ($action=='setdel' && !$error) 
     210      { 
     211        $script_name = get_input_value('_set', RCUBE_INPUT_GPC); 
     212        $result = $this->sieve->remove($script_name); 
     213         
     214        if ($result === true) { 
     215          $this->rc->output->show_message('managesieve.setdeleted', 'confirmation'); 
     216          $this->rc->output->command('managesieve_reload'); 
     217          rcube_sess_unset('managesieve_current'); 
     218        } else { 
     219          $this->rc->output->show_message('managesieve.setdeleteerror', 'error'); 
     220        } 
    166221      } 
    167222      elseif ($action=='ruleadd') 
     
    193248    $error = $this->managesieve_start(); 
    194249 
    195     // add/edit action 
    196     if (isset($_POST['_name'])) 
     250    // filters set add action 
     251    if (!empty($_POST['_newset'])) 
     252    { 
     253      $name = get_input_value('_name', RCUBE_INPUT_GPC); 
     254      $copy = get_input_value('_copy', RCUBE_INPUT_GPC); 
     255 
     256      if (!$name) 
     257        $error = 'managesieve.emptyname'; 
     258      else if (mb_strlen($name)>128) 
     259        $error = 'managesieve.nametoolong'; 
     260      else if (!$this->sieve->copy($name, $copy)) 
     261        $error = 'managesieve.setcreateerror'; 
     262                 
     263      if (!$error) { 
     264        $this->rc->output->show_message('managesieve.setcreated', 'confirmation'); 
     265        $this->rc->output->command('parent.managesieve_reload', $name); 
     266//      rcube_sess_unset('managesieve_current'); 
     267      } else { 
     268        $this->rc->output->show_message($error, 'error'); 
     269      } 
     270    } 
     271    // filter add/edit action 
     272    else if (isset($_POST['_name'])) 
    197273    { 
    198274      $name = trim(get_input_value('_name', RCUBE_INPUT_POST)); 
     
    423499  { 
    424500    // Handle form action  
    425     if (isset($_GET['_framed']) || isset($_POST['_framed'])) 
    426       $this->rc->output->send('managesieve.managesieveedit'); 
    427     else { 
     501    if (isset($_GET['_framed']) || isset($_POST['_framed'])) { 
     502      if (isset($_GET['_newset']) || isset($_POST['_newset'])) 
     503        $this->rc->output->send('managesieve.setedit'); 
     504      else 
     505        $this->rc->output->send('managesieve.filteredit'); 
     506    } else { 
    428507      $this->rc->output->set_pagetitle($this->gettext('filters')); 
    429508      $this->rc->output->send('managesieve.managesieve'); 
     
    452531   
    453532    // add some labels to client 
    454     $this->rc->output->add_label('managesieve.filterconfirmdelete'); 
     533    $this->rc->output->add_label('managesieve.filterdeleteconfirm'); 
     534   
     535    return $out; 
     536  } 
     537 
     538  // return the filters list as <SELECT> 
     539  function filtersets_list($attrib) 
     540  { 
     541    // add id to message list table if not specified 
     542    if (!strlen($attrib['id'])) 
     543      $attrib['id'] = 'rcmfiltersetslist'; 
     544 
     545    $list = $this->sieve->get_scripts(); 
     546    $active = $this->sieve->get_active(); 
     547   
     548    $select = new html_select(array('name' => '_set', 'id' => $attrib['id'], 'onchange' => 'rcmail.managesieve_set()')); 
     549 
     550    asort($list, SORT_LOCALE_STRING); 
     551 
     552    foreach($list as $set) 
     553      $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set); 
     554     
     555    $out = $select->show($this->sieve->current); 
     556     
     557    // set client env 
     558    $this->rc->output->add_gui_object('filtersetslist', $attrib['id']); 
     559    $this->rc->output->add_label('managesieve.setdeleteconfirm'); 
     560    $this->rc->output->add_label('managesieve.active'); 
    455561   
    456562    return $out; 
     
    466572    $this->rc->output->set_env('contentframe', $attrib['name']); 
    467573    $this->rc->output->set_env('blankpage', $attrib['src'] ?  
    468         $this->rc->output->abs_url($attrib['src']) : 'program/blank.gif'); 
     574    $this->rc->output->abs_url($attrib['src']) : 'program/blank.gif'); 
    469575 
    470576    return html::tag('iframe', $attrib); 
     577  } 
     578 
     579 
     580  function filterset_form($attrib) 
     581  { 
     582    if (!$attrib['id']) 
     583      $attrib['id'] = 'rcmfiltersetform'; 
     584 
     585    $out = '<form name="filtersetform" action="./" method="post">'."\n"; 
     586 
     587    $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task)); 
     588    $hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save')); 
     589    $hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0))); 
     590    $hiddenfields->add(array('name' => '_newset', 'value' => 1)); 
     591 
     592    $out .= $hiddenfields->show(); 
     593 
     594    $name = get_input_value('_name', RCUBE_INPUT_GPC); 
     595    $copy = get_input_value('_copy', RCUBE_INPUT_GPC); 
     596 
     597    $table = new html_table(array('cols' => 2)); 
     598 
     599    // filter set name input 
     600    $input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30, 
     601        'class' => ($this->errors['name'] ? 'error' : ''))); 
     602 
     603    $table->add('title', sprintf('<label for="%s"><b>%s:</b></label>', '_name', Q($this->gettext('filtersetname')))); 
     604    $table->add(null, $input_name->show($name)); 
     605 
     606    // filters set list 
     607    $list = $this->sieve->get_scripts(); 
     608    $active = $this->sieve->get_active(); 
     609   
     610    $select = new html_select(array('name' => '_copy', 'id' => '_copy')); 
     611 
     612    asort($list, SORT_LOCALE_STRING); 
     613 
     614    $select->add($this->gettext('none'), ''); 
     615    foreach($list as $set) 
     616      $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set); 
     617     
     618    $table->add('title', '<label>'.$this->gettext('copyfromset').':</label>'); 
     619    $table->add(null, $select->show($copy)); 
     620 
     621    $out .= $table->show(); 
     622     
     623    $this->rc->output->add_gui_object('sieveform', 'filtersetform'); 
     624 
     625    return $out; 
    471626  } 
    472627 
     
    819974  private function check_email($email) 
    820975  { 
    821     if (function_exists('check_email')); 
     976    if (function_exists('check_email'));  
    822977      return check_email($email); 
    823978 
  • trunk/roundcubemail/plugins/managesieve/skins/default/managesieve.css

    r2539 r3085  
    77  left: 20px; 
    88  width: 220px; 
    9   top: 130px; 
     9  top: 120px; 
    1010  bottom: 30px; 
    1111  border: 1px solid #999999; 
     
    3333  position: absolute; 
    3434  left: 20px; 
    35   top: 95px; 
     35  top: 85px; 
     36} 
     37 
     38#filtersetsbuttons 
     39{ 
     40  position: absolute; 
     41  left: 250px; 
     42  top: 85px; 
     43} 
     44 
     45#filtersbuttons a, 
     46#filtersetsbuttons a 
     47{ 
     48  display: block; 
     49  float: left; 
     50} 
     51 
     52#filtersbuttons a.button, 
     53#filtersbuttons a.buttonPas, 
     54#filtersetsbuttons a.button, 
     55#filtersetsbuttons a.buttonPas 
     56{ 
     57  display: block; 
     58  float: left; 
     59  width: 32px; 
     60  height: 32px; 
     61  padding: 0; 
     62  margin-right: 3px; 
     63  overflow: hidden; 
     64  background: url('managesieve_toolbar.png') 0 0 no-repeat transparent; 
     65  opacity: 0.99; /* this is needed to make buttons appear correctly in Chrome */ 
     66} 
     67 
     68#filtersbuttons a.buttonPas, 
     69#filtersetsbuttons a.buttonPas 
     70{ 
     71  filter: alpha(opacity=35); 
     72  opacity: 0.35; 
     73} 
     74 
     75#filtersbuttons a.add { 
     76  background-position: 0px 0px; 
     77} 
     78 
     79#filtersbuttons a.addsel { 
     80  background-position: 0 -32px; 
     81} 
     82 
     83#filtersbuttons a.del { 
     84  background-position: -32px 0px; 
     85} 
     86 
     87#filtersbuttons a.delsel { 
     88  background-position: -32px -32px; 
     89} 
     90 
     91#filtersbuttons a.up { 
     92  background-position: -64px 0px; 
     93} 
     94 
     95#filtersbuttons a.upsel { 
     96  background-position: -64px -32px; 
     97} 
     98 
     99#filtersbuttons a.down { 
     100  background-position: -96px 0px; 
     101} 
     102 
     103#filtersbuttons a.downsel { 
     104  background-position: -96px -32px; 
     105} 
     106 
     107#filtersetsbuttons a.setadd { 
     108  background-position: -128px 0px; 
     109} 
     110 
     111#filtersetsbuttons a.setaddsel { 
     112  background-position: -128px -32px; 
     113} 
     114 
     115#filtersetsbuttons a.setdel { 
     116  background-position: -160px 0px; 
     117} 
     118 
     119#filtersetsbuttons a.setdelsel { 
     120  background-position: -160px -32px; 
     121} 
     122 
     123#filtersetsbuttons a.setset { 
     124  background-position: -192px 0px; 
     125} 
     126 
     127#filtersetsbuttons a.setsetsel { 
     128  background-position: -192px -32px; 
     129} 
     130 
     131#filtersetselect 
     132{ 
     133  position: absolute; 
     134  left: 380px; 
     135  top: 90px; 
    36136} 
    37137 
     
    39139{ 
    40140  position: absolute; 
    41   top: 95px; 
     141  top: 120px; 
    42142  left: 250px; 
    43143  right: 20px; 
     
    47147  /* css hack for IE */ 
    48148  width: expression((parseInt(document.documentElement.clientWidth)-30-parseInt(document.getElementById('filterslist').offsetLeft)-parseInt(document.getElementById('filterslist').offsetWidth))+'px'); 
    49   height: expression((parseInt(document.documentElement.clientHeight)-120)+'px'); 
     149  height: expression((parseInt(document.documentElement.clientHeight)-155)+'px'); 
    50150} 
    51151 
  • trunk/roundcubemail/plugins/managesieve/skins/default/templates/managesieve.html

    r2552 r3085  
    1414 
    1515<div id="filtersbuttons"> 
    16 <roundcube:button command="plugin.managesieve-add" imageSel="/this/filter_add_sel.png" imagePas="/this/filter_add_pas.png" imageAct="/this/filter_add_act.png" width="32" height="32" title="managesieve.filteradd" /> 
    17 <roundcube:button command="plugin.managesieve-del" imageSel="/this/filter_del_sel.png" imagePas="/this/filter_del_pas.png" imageAct="/this/filter_del_act.png"  width="32" height="32" title="managesieve.filterdel" /> 
    18 <roundcube:button command="plugin.managesieve-up" imageSel="/this/filter_up_sel.png" imagePas="/this/filter_up_pas.png" imageAct="/this/filter_up_act.png"  width="32" height="32" title="managesieve.moveup" /> 
    19 <roundcube:button command="plugin.managesieve-down" imageSel="/this/filter_down_sel.png" imagePas="/this/filter_down_pas.png" imageAct="/this/filter_down_act.png"  width="32" height="32" title="managesieve.movedown" /> 
     16<roundcube:button command="plugin.managesieve-add" type="link" class="buttonPas add" classSel="button addsel" classAct="button add" title="managesieve.filteradd" content=" " /> 
     17<roundcube:button command="plugin.managesieve-del" type="link" class="buttonPas del" classSel="button delsel" classAct="button del" title="managesieve.filterdel" content=" " /> 
     18<roundcube:button command="plugin.managesieve-up" type="link" class="buttonPas up" classSel="button upsel" classAct="button up" title="managesieve.moveup" content=" " /> 
     19<roundcube:button command="plugin.managesieve-down" type="link" class="buttonPas down" classSel="button downsel" classAct="button down" title="managesieve.movedown" content=" " /> 
     20</div> 
     21 
     22<div id="filtersetsbuttons"> 
     23<roundcube:button command="plugin.managesieve-setadd" type="link" class="buttonPas setadd" classSel="button setaddsel" classAct="button setadd" title="managesieve.filtersetadd" content=" " /> 
     24<roundcube:button command="plugin.managesieve-setdel" type="link" class="buttonPas setdel" classSel="button setdelsel" classAct="button setdel" title="managesieve.filtersetdel" content=" " /> 
     25<roundcube:button command="plugin.managesieve-setact" type="link" class="buttonPas setset" classSel="button setsetsel" classAct="button setset" title="managesieve.filtersetact" content=" " /> 
     26</div> 
     27<div id="filtersetselect"> 
     28<roundcube:label name="managesieve.filterset" />: 
     29<roundcube:object name="filtersetslist" id="filtersets-select" /> 
    2030</div> 
    2131 
Note: See TracChangeset for help on using the changeset viewer.