From 47d8d39cf49310b688967f7571b0d66b5971b39c Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Sun, 21 Feb 2010 11:44:39 -0500
Subject: [PATCH] Use rcmail::imap_connect() to establish IMAP connections; always initialize rcube_imap object in mail steps

---
 plugins/managesieve/managesieve.php |  342 ++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 256 insertions(+), 86 deletions(-)

diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php
index d29ad34..219c334 100644
--- a/plugins/managesieve/managesieve.php
+++ b/plugins/managesieve/managesieve.php
@@ -7,36 +7,12 @@
  * It's clickable interface which operates on text scripts and communicates
  * with server using managesieve protocol. Adds Filters tab in Settings.
  *
- * @version 1.0
+ * @version 2.2
  * @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl>
  *
- * Configuration (main.inc.php):
- 
-// managesieve server port
-$rcmail_config['managesieve_port'] = 2000;
-
-// managesieve server address
-$rcmail_config['managesieve_host'] = 'localhost';
-
-// use or not TLS for managesieve server connection
-// it's because I've problems with TLS and dovecot's managesieve plugin
-// and it's not needed on localhost
-$rcmail_config['managesieve_usetls'] = false;
-
-// default contents of filters script (eg. default spam filter)
-$rcmail_config['managesieve_default'] = '/etc/dovecot/sieve/global';
-
-// I need this because my dovecot (with listescape plugin) uses
-// ':' delimiter, but creates folders with dot delimiter
-$rcmail_config['managesieve_replace_delimiter'] = '';
-
-// disabled sieve extensions (body, copy, date, editheader, encoded-character,
-// envelope, environment, ereject, fileinto, ihave, imap4flags, index,
-// mailbox, mboxmetadata, regex, reject, relational, servermetadata,
-// spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc.
-// Note: not all extensions are implemented
-$rcmail_config['managesieve_disabled_extensions'] = array();
-
+ * Configuration (see config.inc.php.dist)
+ *
+ * $Id$
  */
 
 class managesieve extends rcube_plugin
@@ -61,7 +37,7 @@
     $this->add_texts('localization/', array('filters','managefilters'));
 
     // register actions
-    $this->register_action('plugin.managesieve', array($this, 'managesieve_init'));
+    $this->register_action('plugin.managesieve', array($this, 'managesieve_actions'));
     $this->register_action('plugin.managesieve-save', array($this, 'managesieve_save'));
 
     // include main js script
@@ -73,39 +49,73 @@
     $rcmail = rcmail::get_instance();
     $this->rc = &$rcmail;
 
+    $this->load_config();
+
     // register UI objects
     $this->rc->output->add_handlers(array(
 	'filterslist' => array($this, 'filters_list'),
+	'filtersetslist' => array($this, 'filtersets_list'),
 	'filterframe' => array($this, 'filter_frame'),
 	'filterform' => array($this, 'filter_form'),
+	'filtersetform' => array($this, 'filterset_form'),
     ));
 
     require_once($this->home . '/lib/Net/Sieve.php');
     require_once($this->home . '/lib/rcube_sieve.php');
 
+    $host = str_replace('%h', $_SESSION['imap_host'], $this->rc->config->get('managesieve_host', 'localhost'));
+    $port = $this->rc->config->get('managesieve_port', 2000);
+
     // try to connect to managesieve server and to fetch the script
     $this->sieve = new rcube_sieve($_SESSION['username'],
 	$this->rc->decrypt($_SESSION['password']), 
-	$this->rc->config->get('managesieve_host', 'localhost'),
-	$this->rc->config->get('managesieve_port', 2000),
+	$host, $port,
 	$this->rc->config->get('managesieve_usetls', false),
-	$this->rc->config->get('managesieve_disabled_extensions'));
+	$this->rc->config->get('managesieve_disabled_extensions'),
+	$this->rc->config->get('managesieve_debug', false)
+    );
 
-    $error = $this->sieve->error();
+    if (!($error = $this->sieve->error())) {
+      
+      $list = $this->sieve->get_scripts();
+      $active = $this->sieve->get_active();
+      $_SESSION['managesieve_active'] = $active;
+      
+      if (!empty($_GET['_sid'])) {
+        $script_name = get_input_value('_sid', RCUBE_INPUT_GET);
+      } else if (!empty($_SESSION['managesieve_current'])) {
+        $script_name = $_SESSION['managesieve_current'];
+      } else {
+        // get active script
+	if ($active) {
+	  $script_name = $active;
+        } else if ($list) {
+          $script_name = $list[0];
+        // create a new (initial) script
+        } else {
+          // if script not exists build default script contents
+          $script_file = $this->rc->config->get('managesieve_default');
+	  $script_name = 'roundcube';
+          if ($script_file && is_readable($script_file))
+	    $content = file_get_contents($script_file);
 
-    if ($error == SIEVE_ERROR_NOT_EXISTS)
-    {
-      // if script not exists build default script contents
-      $script_file = $this->rc->config->get('managesieve_default');
-      if ($script_file && is_readable($script_file))
-	$this->sieve->script->add_text(file_get_contents($script_file)); 
-      // that's not exactly an error
-      $error = false;
+	  // add script and set it active    
+	  if ($this->sieve->save_script($script_name, $content)) 
+            if ($this->sieve->activate($script_name))
+	      $_SESSION['managesieve_active'] = $script_name;
+	}
+      }
+
+      if ($script_name)
+        $this->sieve->load($script_name);
+
+      $error = $this->sieve->error();
     }
-    elseif ($error)
+    
+    // finally set script objects
+    if ($error)
     {
-      switch ($error)
-      {
+      switch ($error) {
 	case SIEVE_ERROR_CONNECTION:
 	case SIEVE_ERROR_LOGIN:
           $this->rc->output->show_message('managesieve.filterconnerror', 'error');  
@@ -115,25 +125,24 @@
 	break;
       }
 
+      raise_error(array('code' => 403, 'type' => 'php', 'message' => "Unable to connect to managesieve on $host:$port"), true, false);
+
       // to disable 'Add filter' button set env variable
       $this->rc->output->set_env('filterconnerror', true);
-    }
-
-    // finally set script objects
-    if ($error)
-    {
       $this->script = array();
     }
     else
     {
       $this->script = $this->sieve->script->as_array();
       $this->exts = $this->sieve->get_extensions();
+      $this->rc->output->set_env('active_set', $_SESSION['managesieve_active']);
+      $_SESSION['managesieve_current'] = $this->sieve->current;
     }
     
     return $error;
   }
 
-  function managesieve_init()
+  function managesieve_actions()
   {
     // Init plugin and handle managesieve connection
     $error = $this->managesieve_start();
@@ -158,7 +167,7 @@
             $this->rc->output->show_message('managesieve.filtersaveerror', 'error');
         }
       }
-      elseif ($action=='down' && !$error)
+      else if ($action=='down' && !$error)
       {
         if (isset($this->script[$fid]) && isset($this->script[$fid+1]))
         {
@@ -166,27 +175,56 @@
     		&& $this->sieve->script->update_rule($fid+1, $this->script[$fid]) !== false)
 	    $result = $this->sieve->save();
       
-          if ($result) {
+          if ($result === true) {
 //          $this->rc->output->show_message('managesieve.filtersaved', 'confirmation');
 	    $this->rc->output->command('managesieve_updatelist', 'down', '', $fid);
-          } else
+          } else {
             $this->rc->output->show_message('managesieve.filtersaveerror', 'error');
-        }
+          }
+	}
       }
-      elseif ($action=='delete' && !$error)
+      else if ($action=='delete' && !$error)
       {
         if (isset($this->script[$fid]))
         {
           if ($this->sieve->script->delete_rule($fid))
             $result = $this->sieve->save();
 
-          if (!$result)
-            $this->rc->output->show_message('managesieve.filterdeleteerror', 'error');
-          else {
+          if ($result === true) {
 	    $this->rc->output->show_message('managesieve.filterdeleted', 'confirmation');
 	    $this->rc->output->command('managesieve_updatelist', 'delete', '', $fid);
+          } else {
+            $this->rc->output->show_message('managesieve.filterdeleteerror', 'error');
           }
-        }
+	}
+      }
+      else if ($action=='setact' && !$error)
+      {
+        $script_name = get_input_value('_set', RCUBE_INPUT_GPC);
+	$result = $this->sieve->activate($script_name);
+	
+	if ($result === true) {
+          $this->rc->output->set_env('active_set', $script_name);
+	  $this->rc->output->show_message('managesieve.setactivated', 'confirmation');
+	  $this->rc->output->command('enable_command', 'plugin.managesieve-setact', false);
+	  $this->rc->output->command('managesieve_reset', $script_name);
+	  $_SESSION['managesieve_active'] = $script_name;
+	} else {
+          $this->rc->output->show_message('managesieve.setactivateerror', 'error');
+	}
+      }
+      else if ($action=='setdel' && !$error)
+      {
+        $script_name = get_input_value('_set', RCUBE_INPUT_GPC);
+	$result = $this->sieve->remove($script_name);
+	
+	if ($result === true) {
+	  $this->rc->output->show_message('managesieve.setdeleted', 'confirmation');
+	  $this->rc->output->command('managesieve_reload');
+	  rcube_sess_unset('managesieve_current');
+	} else {
+          $this->rc->output->show_message('managesieve.setdeleteerror', 'error');
+	}
       }
       elseif ($action=='ruleadd')
       {
@@ -216,10 +254,31 @@
     // Init plugin and handle managesieve connection
     $error = $this->managesieve_start();
 
-    // add/edit action
-    if (isset($_POST['_name']))
+    // filters set add action
+    if (!empty($_POST['_newset']))
     {
-      $name = trim(get_input_value('_name', RCUBE_INPUT_POST));
+      $name = get_input_value('_name', RCUBE_INPUT_GPC);
+      $copy = get_input_value('_copy', RCUBE_INPUT_GPC);
+
+      if (!$name)
+	$error = 'managesieve.emptyname';
+      else if (mb_strlen($name)>128)
+	$error = 'managesieve.nametoolong';
+      else if (!$this->sieve->copy($name, $copy))
+	$error = 'managesieve.setcreateerror';
+		
+      if (!$error) {
+	$this->rc->output->show_message('managesieve.setcreated', 'confirmation');
+	$this->rc->output->command('parent.managesieve_reload', $name);
+//	rcube_sess_unset('managesieve_current');
+      } else {
+        $this->rc->output->show_message($error, 'error');
+      }
+    }
+    // filter add/edit action
+    else if (isset($_POST['_name']))
+    {
+      $name = trim(get_input_value('_name', RCUBE_INPUT_POST, true));
       $fid = trim(get_input_value('_fid', RCUBE_INPUT_POST));
       $join = trim(get_input_value('_join', RCUBE_INPUT_POST));
   
@@ -266,7 +325,7 @@
       else foreach($headers as $idx => $header)
       {
 	$header = $this->strip_value($header);
-	$target = $this->strip_value($targets[$idx]);
+	$target = $this->strip_value($targets[$idx], true);
 	$op = $this->strip_value($ops[$idx]);
 
 	// normal header
@@ -308,7 +367,7 @@
 		$this->errors['tests'][$i]['sizetarget'] = $this->gettext('wrongformat');
 	      break;
 	    case '...':
-              $cust_header = $this->strip_value($cust_headers[$idx]);
+              $cust_header = $headers = $this->strip_value($cust_headers[$idx]);
 
               if(preg_match('/^not/', $op))
 		$this->form['tests'][$i]['not'] = true;
@@ -316,10 +375,22 @@
 
               if ($cust_header == '')
     		$this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty');
-              elseif (!preg_match('/^[a-z0-9-]+$/i', $cust_header))
-    		$this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars');
-
-              if ($type == 'exists')
+              else {
+	        $headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY);
+	        
+		if (!count($headers))
+    		  $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty');
+		else {
+		  foreach ($headers as $hr)
+		    if (!preg_match('/^[a-z0-9-]+$/i', $hr))
+    		      $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars');
+		}
+	      }
+	      
+	      if (empty($this->errors['tests'][$i]['header']))
+		$cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers;
+              
+	      if ($type == 'exists')
     	      {
 		$this->form['tests'][$i]['test'] = 'exists';
     		$this->form['tests'][$i]['arg'] = $cust_header;
@@ -416,9 +487,7 @@
 	{
 	  $this->rc->output->show_message('managesieve.filtersaved', 'confirmation');
 	  $this->rc->output->add_script(sprintf("rcmail.managesieve_updatelist('%s', '%s', %d);",
-	    isset($new) ? 'add' : 'update', $this->form['name'], $fid), 'foot');
-//	  $this->rc->output->command('managesieve_updatelist', isset($new) ? 'add' : 'update', $this->form['name'], $fid);
-//	  $this->rc->output->send();
+	    isset($new) ? 'add' : 'update', Q($this->form['name']), $fid), 'foot');
 	}
 	else
 	{
@@ -434,9 +503,12 @@
   private function managesieve_send()
   {
     // Handle form action 
-    if (isset($_GET['_framed']) || isset($_POST['_framed']))
-      $this->rc->output->send('managesieve.managesieveedit');
-    else {
+    if (isset($_GET['_framed']) || isset($_POST['_framed'])) {
+      if (isset($_GET['_newset']) || isset($_POST['_newset']))
+        $this->rc->output->send('managesieve.setedit');
+      else
+        $this->rc->output->send('managesieve.filteredit');
+    } else {
       $this->rc->output->set_pagetitle($this->gettext('filters'));
       $this->rc->output->send('managesieve.managesieve');
     }
@@ -463,7 +535,36 @@
     $this->rc->output->include_script('list.js');
   
     // add some labels to client
-    $this->rc->output->add_label('managesieve.filterconfirmdelete');
+    $this->rc->output->add_label('managesieve.filterdeleteconfirm');
+  
+    return $out;
+  }
+
+  // return the filters list as <SELECT>
+  function filtersets_list($attrib)
+  {
+    // add id to message list table if not specified
+    if (!strlen($attrib['id']))
+      $attrib['id'] = 'rcmfiltersetslist';
+
+    $list = $this->sieve->get_scripts();
+    $active = $this->sieve->get_active();
+  
+    $select = new html_select(array('name' => '_set', 'id' => $attrib['id'], 'onchange' => 'rcmail.managesieve_set()'));
+
+    if ($list) {
+      asort($list, SORT_LOCALE_STRING);
+
+      foreach($list as $set)
+        $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set);
+    }
+    
+    $out = $select->show($this->sieve->current);
+    
+    // set client env
+    $this->rc->output->add_gui_object('filtersetslist', $attrib['id']);
+    $this->rc->output->add_label('managesieve.setdeleteconfirm');
+    $this->rc->output->add_label('managesieve.active');
   
     return $out;
   }
@@ -477,9 +578,58 @@
 
     $this->rc->output->set_env('contentframe', $attrib['name']);
     $this->rc->output->set_env('blankpage', $attrib['src'] ? 
-	$this->rc->output->abs_url($attrib['src']) : 'program/blank.gif');
+    $this->rc->output->abs_url($attrib['src']) : 'program/blank.gif');
 
     return html::tag('iframe', $attrib);
+  }
+
+
+  function filterset_form($attrib)
+  {
+    if (!$attrib['id'])
+      $attrib['id'] = 'rcmfiltersetform';
+
+    $out = '<form name="filtersetform" action="./" method="post">'."\n";
+
+    $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
+    $hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
+    $hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
+    $hiddenfields->add(array('name' => '_newset', 'value' => 1));
+
+    $out .= $hiddenfields->show();
+
+    $name = get_input_value('_name', RCUBE_INPUT_GPC);
+    $copy = get_input_value('_copy', RCUBE_INPUT_GPC);
+
+    $table = new html_table(array('cols' => 2));
+
+    // filter set name input
+    $input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30,
+	'class' => ($this->errors['name'] ? 'error' : '')));
+
+    $table->add('title', sprintf('<label for="%s"><b>%s:</b></label>', '_name', Q($this->gettext('filtersetname'))));
+    $table->add(null, $input_name->show($name));
+
+    // filters set list
+    $list = $this->sieve->get_scripts();
+    $active = $this->sieve->get_active();
+  
+    $select = new html_select(array('name' => '_copy', 'id' => '_copy'));
+
+    asort($list, SORT_LOCALE_STRING);
+
+    $select->add($this->gettext('none'), '');
+    foreach($list as $set)
+      $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set);
+    
+    $table->add('title', '<label>'.$this->gettext('copyfromset').':</label>');
+    $table->add(null, $select->show($copy));
+
+    $out .= $table->show();
+    
+    $this->rc->output->add_gui_object('sieveform', 'filtersetform');
+
+    return $out;
   }
 
 
@@ -599,9 +749,11 @@
 
     // TODO: list arguments
 
-    if ((isset($rule['test']) && $rule['test'] == 'header') && in_array($rule['arg1'], $this->headers))
+    if ((isset($rule['test']) && $rule['test'] == 'header')
+	&& !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers))
       $out .= $select_header->show($rule['arg1']);
-    elseif ((isset($rule['test']) && $rule['test'] == 'exists') && in_array($rule['arg'], $this->headers))
+    elseif ((isset($rule['test']) && $rule['test'] == 'exists')
+	&& !is_array($rule['arg']) && in_array($rule['arg'], $this->headers))
       $out .= $select_header->show($rule['arg']);
     elseif (isset($rule['test']) && $rule['test'] == 'size')
       $out .= $select_header->show('size');
@@ -612,10 +764,12 @@
 
     $out .= '</td><td class="rowtargets">';
 
-    if ((isset($rule['test']) && $rule['test'] == 'header') && !in_array($rule['arg1'], $this->headers))
-      $custom = $rule['arg1'];
-    elseif ((isset($rule['test']) && $rule['test'] == 'exists') && !in_array($rule['arg'], $this->headers))
-      $custom = $rule['arg'];
+    if ((isset($rule['test']) && $rule['test'] == 'header')
+	&& (is_array($rule['arg1']) || !in_array($rule['arg1'], $this->headers)))
+      $custom = is_array($rule['arg1']) ? implode(', ', $rule['arg1']) : $rule['arg1'];
+    elseif ((isset($rule['test']) && $rule['test'] == 'exists')
+	&& (is_array($rule['arg']) || !in_array($rule['arg'], $this->headers)))
+      $custom = is_array($rule['arg']) ? implode(', ', $rule['arg']) : $rule['arg'];
     
     $out .= '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '">
 	<input type="text" name="_custom_header[]" '. $this->error_class($id, 'test', 'header')
@@ -747,10 +901,13 @@
     $out .= '<select id="action_mailbox' .$id. '" name="_action_mailbox[]" style="display:' 
 	.(!isset($action) || $action['type']=='fileinto' ? 'inline' : 'none'). '">';
 
-    $this->rc->imap_init(true);
+    $this->rc->imap_connect();
 
     $a_folders = $this->rc->imap->list_mailboxes();
     $delimiter = $this->rc->imap->get_hierarchy_delimiter();
+
+    // set mbox encoding
+    $mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP'); 
 
     if ($action['type'] == 'fileinto')
       $mailbox = $action['target'];
@@ -759,12 +916,15 @@
 
     foreach ($a_folders as $folder)
     {
-      $utf7folder = $folder;
+      $utf7folder = $this->rc->imap->mod_mailbox($folder);
       $names = explode($delimiter, rcube_charset_convert($folder, 'UTF7-IMAP'));
       $name = $names[sizeof($names)-1];
     
       if ($replace_delimiter = $this->rc->config->get('managesieve_replace_delimiter'))
         $utf7folder = str_replace($delimiter, $replace_delimiter, $utf7folder);
+    
+      // convert to Sieve implementation encoding
+      $utf7folder = $this->mbox_encode($utf7folder, $mbox_encoding);
     
       if ($folder_class = rcmail_folder_classname($name))
         $foldername = $this->gettext($folder_class);
@@ -802,9 +962,12 @@
     return $result;
   }
 
-  private function strip_value($str)
+  private function strip_value($str, $allow_html=false)
   {
-    return trim(strip_tags($str));
+    if (!$allow_html)
+      $str = strip_tags($str);
+       
+    return trim($str);
   }
 
   private function error_class($id, $type, $target, $name_only=false)
@@ -820,6 +983,9 @@
 
   private function check_email($email)
   {
+    if (function_exists('check_email')); 
+      return check_email($email);
+
     // Check for invalid characters
     if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email))
       return false;
@@ -857,6 +1023,10 @@
     return false;
   }
  
+  private function mbox_encode($text, $encoding)
+  {
+    return rcube_charset_convert($text, 'UTF7-IMAP', $encoding);
+  }
 }
 
 ?>

--
Gitblit v1.9.1