4 * Classes for managesieve operations (using PEAR::Net_Sieve)
6 * Copyright (C) 2008-2011, The Roundcube Dev Team
7 * Copyright (C) 2011, Kolab Systems AG
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * $Id: rcube_sieve.php 5452 2011-11-18 14:44:48Z alec $
26 // Managesieve Protocol: RFC5804
28 define('SIEVE_ERROR_CONNECTION', 1);
29 define('SIEVE_ERROR_LOGIN', 2);
30 define('SIEVE_ERROR_NOT_EXISTS', 3); // script not exists
31 define('SIEVE_ERROR_INSTALL', 4); // script installation
32 define('SIEVE_ERROR_ACTIVATE', 5); // script activation
33 define('SIEVE_ERROR_DELETE', 6); // script deletion
34 define('SIEVE_ERROR_INTERNAL', 7); // internal error
35 define('SIEVE_ERROR_DEACTIVATE', 8); // script activation
36 define('SIEVE_ERROR_OTHER', 255); // other/unknown error
41 private $sieve; // Net_Sieve object
42 private $error = false; // error flag
43 private $list = array(); // scripts list
45 public $script; // rcube_sieve_script object
46 public $current; // name of currently loaded script
47 private $exts; // array of supported extensions
53 * @param string Username (for managesieve login)
54 * @param string Password (for managesieve login)
55 * @param string Managesieve server hostname/address
56 * @param string Managesieve server port number
57 * @param string Managesieve authentication method
58 * @param boolean Enable/disable TLS use
59 * @param array Disabled extensions
60 * @param boolean Enable/disable debugging
61 * @param string Proxy authentication identifier
62 * @param string Proxy authentication password
64 public function __construct($username, $password='', $host='localhost', $port=2000,
65 $auth_type=null, $usetls=true, $disabled=array(), $debug=false,
66 $auth_cid=null, $auth_pw=null)
68 $this->sieve = new Net_Sieve();
71 $this->sieve->setDebug(true, array($this, 'debug_handler'));
74 if (PEAR::isError($this->sieve->connect($host, $port, null, $usetls))) {
75 return $this->_set_error(SIEVE_ERROR_CONNECTION);
78 if (!empty($auth_cid)) {
80 $username = $auth_cid;
84 if (PEAR::isError($this->sieve->login($username, $password,
85 $auth_type ? strtoupper($auth_type) : null, $authz))
87 return $this->_set_error(SIEVE_ERROR_LOGIN);
90 $this->exts = $this->get_extensions();
92 // disable features by config
93 if (!empty($disabled)) {
94 // we're working on lower-cased names
95 $disabled = array_map('strtolower', (array) $disabled);
96 foreach ($disabled as $ext) {
97 if (($idx = array_search($ext, $this->exts)) !== false) {
98 unset($this->exts[$idx]);
104 public function __destruct() {
105 $this->sieve->disconnect();
109 * Getter for error code
111 public function error()
113 return $this->error ? $this->error : false;
117 * Saves current script into server
119 public function save($name = null)
122 return $this->_set_error(SIEVE_ERROR_INTERNAL);
125 return $this->_set_error(SIEVE_ERROR_INTERNAL);
128 $name = $this->current;
130 $script = $this->script->as_text();
133 $script = '/* empty script */';
135 if (PEAR::isError($this->sieve->installScript($name, $script)))
136 return $this->_set_error(SIEVE_ERROR_INSTALL);
142 * Saves text script into server
144 public function save_script($name, $content = null)
147 return $this->_set_error(SIEVE_ERROR_INTERNAL);
150 $content = '/* empty script */';
152 if (PEAR::isError($this->sieve->installScript($name, $content)))
153 return $this->_set_error(SIEVE_ERROR_INSTALL);
159 * Activates specified script
161 public function activate($name = null)
164 return $this->_set_error(SIEVE_ERROR_INTERNAL);
167 $name = $this->current;
169 if (PEAR::isError($this->sieve->setActive($name)))
170 return $this->_set_error(SIEVE_ERROR_ACTIVATE);
176 * De-activates specified script
178 public function deactivate()
181 return $this->_set_error(SIEVE_ERROR_INTERNAL);
183 if (PEAR::isError($this->sieve->setActive('')))
184 return $this->_set_error(SIEVE_ERROR_DEACTIVATE);
190 * Removes specified script
192 public function remove($name = null)
195 return $this->_set_error(SIEVE_ERROR_INTERNAL);
198 $name = $this->current;
200 // script must be deactivated first
201 if ($name == $this->sieve->getActive())
202 if (PEAR::isError($this->sieve->setActive('')))
203 return $this->_set_error(SIEVE_ERROR_DELETE);
205 if (PEAR::isError($this->sieve->removeScript($name)))
206 return $this->_set_error(SIEVE_ERROR_DELETE);
208 if ($name == $this->current)
209 $this->current = null;
215 * Gets list of supported by server Sieve extensions
217 public function get_extensions()
223 return $this->_set_error(SIEVE_ERROR_INTERNAL);
225 $ext = $this->sieve->getExtensions();
226 // we're working on lower-cased names
227 $ext = array_map('strtolower', (array) $ext);
230 $supported = $this->script->get_extensions();
231 foreach ($ext as $idx => $ext_name)
232 if (!in_array($ext_name, $supported))
236 return array_values($ext);
240 * Gets list of scripts from server
242 public function get_scripts()
247 return $this->_set_error(SIEVE_ERROR_INTERNAL);
249 $list = $this->sieve->listScripts();
251 if (PEAR::isError($list))
252 return $this->_set_error(SIEVE_ERROR_OTHER);
261 * Returns active script name
263 public function get_active()
266 return $this->_set_error(SIEVE_ERROR_INTERNAL);
268 return $this->sieve->getActive();
272 * Loads script by name
274 public function load($name)
277 return $this->_set_error(SIEVE_ERROR_INTERNAL);
279 if ($this->current == $name)
282 $script = $this->sieve->getScript($name);
284 if (PEAR::isError($script))
285 return $this->_set_error(SIEVE_ERROR_OTHER);
287 // try to parse from Roundcube format
288 $this->script = $this->_parse($script);
290 $this->current = $name;
296 * Loads script from text content
298 public function load_script($script)
301 return $this->_set_error(SIEVE_ERROR_INTERNAL);
303 // try to parse from Roundcube format
304 $this->script = $this->_parse($script);
308 * Creates rcube_sieve_script object from text script
310 private function _parse($txt)
313 $script = new rcube_sieve_script($txt, $this->exts);
315 // fix/convert to Roundcube format
316 if (!empty($script->content)) {
317 // replace all elsif with if+stop, we support only ifs
318 foreach ($script->content as $idx => $rule) {
319 if (empty($rule['type']) || !preg_match('/^(if|elsif|else)$/', $rule['type'])) {
323 $script->content[$idx]['type'] = 'if';
326 foreach ($rule['actions'] as $action) {
327 if (preg_match('/^(stop|vacation)$/', $action['type'])) {
331 if (empty($script->content[$idx+1]) || $script->content[$idx+1]['type'] != 'if') {
332 $script->content[$idx]['actions'][] = array('type' => 'stop');
341 * Gets specified script as text
343 public function get_script($name)
346 return $this->_set_error(SIEVE_ERROR_INTERNAL);
348 $content = $this->sieve->getScript($name);
350 if (PEAR::isError($content))
351 return $this->_set_error(SIEVE_ERROR_OTHER);
357 * Creates empty script or copy of other script
359 public function copy($name, $copy)
362 return $this->_set_error(SIEVE_ERROR_INTERNAL);
365 $content = $this->sieve->getScript($copy);
367 if (PEAR::isError($content))
368 return $this->_set_error(SIEVE_ERROR_OTHER);
371 return $this->save_script($name, $content);
374 private function _set_error($error)
376 $this->error = $error;
381 * This is our own debug handler for connection
383 public function debug_handler(&$sieve, $message)
385 write_log('sieve', preg_replace('/\r\n$/', '', $message));