commit | author | age
|
a393c3
|
1 |
<?php |
A |
2 |
|
|
3 |
/** |
|
4 |
* Managesieve (Sieve Filters) |
|
5 |
* |
|
6 |
* Plugin that adds a possibility to manage Sieve filters in Thunderbird's style. |
|
7 |
* It's clickable interface which operates on text scripts and communicates |
|
8 |
* with server using managesieve protocol. Adds Filters tab in Settings. |
|
9 |
* |
fcc34c
|
10 |
* @version 1.7 |
a393c3
|
11 |
* @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl> |
A |
12 |
* |
9240c6
|
13 |
* Configuration (see config.inc.php.dist): |
a393c3
|
14 |
*/ |
A |
15 |
|
|
16 |
class managesieve extends rcube_plugin |
|
17 |
{ |
|
18 |
public $task = 'settings'; |
|
19 |
|
|
20 |
private $rc; |
5d90e1
|
21 |
private $sieve; |
a393c3
|
22 |
private $errors; |
A |
23 |
private $form; |
|
24 |
private $script = array(); |
|
25 |
private $exts = array(); |
|
26 |
private $headers = array( |
|
27 |
'subject' => 'Subject', |
|
28 |
'sender' => 'From', |
|
29 |
'recipient' => 'To', |
|
30 |
); |
|
31 |
|
|
32 |
function init() |
|
33 |
{ |
|
34 |
// add Tab label/title |
|
35 |
$this->add_texts('localization/', array('filters','managefilters')); |
|
36 |
|
|
37 |
// register actions |
|
38 |
$this->register_action('plugin.managesieve', array($this, 'managesieve_init')); |
|
39 |
$this->register_action('plugin.managesieve-save', array($this, 'managesieve_save')); |
|
40 |
|
|
41 |
// include main js script |
|
42 |
$this->include_script('managesieve.js'); |
|
43 |
} |
|
44 |
|
|
45 |
function managesieve_start() |
|
46 |
{ |
5d90e1
|
47 |
$rcmail = rcmail::get_instance(); |
A |
48 |
$this->rc = &$rcmail; |
|
49 |
|
9240c6
|
50 |
$this->load_config(); |
A |
51 |
|
a393c3
|
52 |
// register UI objects |
A |
53 |
$this->rc->output->add_handlers(array( |
|
54 |
'filterslist' => array($this, 'filters_list'), |
|
55 |
'filterframe' => array($this, 'filter_frame'), |
|
56 |
'filterform' => array($this, 'filter_form'), |
|
57 |
)); |
|
58 |
|
|
59 |
require_once($this->home . '/lib/Net/Sieve.php'); |
|
60 |
require_once($this->home . '/lib/rcube_sieve.php'); |
|
61 |
|
|
62 |
// try to connect to managesieve server and to fetch the script |
|
63 |
$this->sieve = new rcube_sieve($_SESSION['username'], |
|
64 |
$this->rc->decrypt($_SESSION['password']), |
1029fc
|
65 |
str_replace('%h', $_SESSION['imap_host'], $this->rc->config->get('managesieve_host', 'localhost')), |
a393c3
|
66 |
$this->rc->config->get('managesieve_port', 2000), |
A |
67 |
$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) |
|
73 |
{ |
|
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 |
{ |
|
85 |
case SIEVE_ERROR_CONNECTION: |
|
86 |
case SIEVE_ERROR_LOGIN: |
|
87 |
$this->rc->output->show_message('managesieve.filterconnerror', 'error'); |
|
88 |
break; |
|
89 |
default: |
|
90 |
$this->rc->output->show_message('managesieve.filterunknownerror', 'error'); |
|
91 |
break; |
|
92 |
} |
|
93 |
|
|
94 |
// to disable 'Add filter' button set env variable |
|
95 |
$this->rc->output->set_env('filterconnerror', true); |
|
96 |
} |
|
97 |
|
|
98 |
// finally set script objects |
|
99 |
if ($error) |
|
100 |
{ |
|
101 |
$this->script = array(); |
|
102 |
} |
|
103 |
else |
|
104 |
{ |
|
105 |
$this->script = $this->sieve->script->as_array(); |
|
106 |
$this->exts = $this->sieve->get_extensions(); |
|
107 |
} |
|
108 |
|
|
109 |
return $error; |
|
110 |
} |
|
111 |
|
|
112 |
function managesieve_init() |
|
113 |
{ |
|
114 |
// Init plugin and handle managesieve connection |
|
115 |
$error = $this->managesieve_start(); |
|
116 |
|
|
117 |
// Handle user requests |
|
118 |
if ($action = get_input_value('_act', RCUBE_INPUT_GPC)) |
|
119 |
{ |
|
120 |
$fid = (int) get_input_value('_fid', RCUBE_INPUT_GET); |
|
121 |
|
|
122 |
if ($action=='up' && !$error) |
|
123 |
{ |
|
124 |
if ($fid && isset($this->script[$fid]) && isset($this->script[$fid-1])) |
|
125 |
{ |
|
126 |
if ($this->sieve->script->update_rule($fid, $this->script[$fid-1]) !== false |
|
127 |
&& $this->sieve->script->update_rule($fid-1, $this->script[$fid]) !== false) |
|
128 |
$result = $this->sieve->save(); |
|
129 |
|
|
130 |
if ($result) { |
|
131 |
// $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); |
|
132 |
$this->rc->output->command('managesieve_updatelist', 'up', '', $fid); |
|
133 |
} else |
|
134 |
$this->rc->output->show_message('managesieve.filtersaveerror', 'error'); |
|
135 |
} |
|
136 |
} |
|
137 |
elseif ($action=='down' && !$error) |
|
138 |
{ |
|
139 |
if (isset($this->script[$fid]) && isset($this->script[$fid+1])) |
|
140 |
{ |
|
141 |
if ($this->sieve->script->update_rule($fid, $this->script[$fid+1]) !== false |
|
142 |
&& $this->sieve->script->update_rule($fid+1, $this->script[$fid]) !== false) |
|
143 |
$result = $this->sieve->save(); |
|
144 |
|
|
145 |
if ($result) { |
|
146 |
// $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); |
|
147 |
$this->rc->output->command('managesieve_updatelist', 'down', '', $fid); |
|
148 |
} else |
|
149 |
$this->rc->output->show_message('managesieve.filtersaveerror', 'error'); |
|
150 |
} |
|
151 |
} |
|
152 |
elseif ($action=='delete' && !$error) |
|
153 |
{ |
|
154 |
if (isset($this->script[$fid])) |
|
155 |
{ |
|
156 |
if ($this->sieve->script->delete_rule($fid)) |
|
157 |
$result = $this->sieve->save(); |
|
158 |
|
|
159 |
if (!$result) |
|
160 |
$this->rc->output->show_message('managesieve.filterdeleteerror', 'error'); |
|
161 |
else { |
|
162 |
$this->rc->output->show_message('managesieve.filterdeleted', 'confirmation'); |
|
163 |
$this->rc->output->command('managesieve_updatelist', 'delete', '', $fid); |
|
164 |
} |
|
165 |
} |
|
166 |
} |
|
167 |
elseif ($action=='ruleadd') |
|
168 |
{ |
|
169 |
$rid = get_input_value('_rid', RCUBE_INPUT_GPC); |
|
170 |
$id = $this->genid(); |
|
171 |
$content = $this->rule_div($fid, $id, false); |
|
172 |
|
|
173 |
$this->rc->output->command('managesieve_rulefill', $content, $id, $rid); |
|
174 |
} |
|
175 |
elseif ($action=='actionadd') |
|
176 |
{ |
|
177 |
$aid = get_input_value('_aid', RCUBE_INPUT_GPC); |
|
178 |
$id = $this->genid(); |
|
179 |
$content = $this->action_div($fid, $id, false); |
|
180 |
|
|
181 |
$this->rc->output->command('managesieve_actionfill', $content, $id, $aid); |
|
182 |
} |
|
183 |
|
|
184 |
$this->rc->output->send(); |
|
185 |
} |
|
186 |
|
|
187 |
$this->managesieve_send(); |
|
188 |
} |
|
189 |
|
|
190 |
function managesieve_save() |
|
191 |
{ |
|
192 |
// Init plugin and handle managesieve connection |
|
193 |
$error = $this->managesieve_start(); |
|
194 |
|
|
195 |
// add/edit action |
|
196 |
if (isset($_POST['_name'])) |
|
197 |
{ |
|
198 |
$name = trim(get_input_value('_name', RCUBE_INPUT_POST)); |
|
199 |
$fid = trim(get_input_value('_fid', RCUBE_INPUT_POST)); |
|
200 |
$join = trim(get_input_value('_join', RCUBE_INPUT_POST)); |
|
201 |
|
|
202 |
// and arrays |
|
203 |
$headers = $_POST['_header']; |
|
204 |
$cust_headers = $_POST['_custom_header']; |
|
205 |
$ops = $_POST['_rule_op']; |
|
206 |
$sizeops = $_POST['_rule_size_op']; |
|
207 |
$sizeitems = $_POST['_rule_size_item']; |
|
208 |
$sizetargets = $_POST['_rule_size_target']; |
|
209 |
$targets = $_POST['_rule_target']; |
|
210 |
$act_types = $_POST['_action_type']; |
|
211 |
$mailboxes = $_POST['_action_mailbox']; |
|
212 |
$act_targets = $_POST['_action_target']; |
|
213 |
$area_targets = $_POST['_action_target_area']; |
|
214 |
$reasons = $_POST['_action_reason']; |
|
215 |
$addresses = $_POST['_action_addresses']; |
|
216 |
$days = $_POST['_action_days']; |
|
217 |
|
|
218 |
// we need a "hack" for radiobuttons |
|
219 |
foreach ($sizeitems as $item) |
|
220 |
$items[] = $item; |
|
221 |
|
|
222 |
$this->form['join'] = $join=='allof' ? true : false; |
|
223 |
$this->form['name'] = $name; |
|
224 |
$this->form['tests'] = array(); |
|
225 |
$this->form['actions'] = array(); |
|
226 |
|
|
227 |
if ($name == '') |
|
228 |
$this->errors['name'] = $this->gettext('cannotbeempty'); |
|
229 |
else |
|
230 |
foreach($this->script as $idx => $rule) |
|
231 |
if($rule['name'] == $name && $idx != $fid) { |
|
232 |
$this->errors['name'] = $this->gettext('ruleexist'); |
|
233 |
break; |
|
234 |
} |
|
235 |
|
|
236 |
$i = 0; |
|
237 |
// rules |
|
238 |
if ($join == 'any') |
|
239 |
{ |
|
240 |
$this->form['tests'][0]['test'] = 'true'; |
|
241 |
} |
|
242 |
else foreach($headers as $idx => $header) |
|
243 |
{ |
|
244 |
$header = $this->strip_value($header); |
|
245 |
$target = $this->strip_value($targets[$idx]); |
|
246 |
$op = $this->strip_value($ops[$idx]); |
|
247 |
|
|
248 |
// normal header |
|
249 |
if (in_array($header, $this->headers)) |
|
250 |
{ |
|
251 |
if(preg_match('/^not/', $op)) |
|
252 |
$this->form['tests'][$i]['not'] = true; |
|
253 |
$type = preg_replace('/^not/', '', $op); |
|
254 |
|
|
255 |
if ($type == 'exists') |
|
256 |
{ |
|
257 |
$this->form['tests'][$i]['test'] = 'exists'; |
|
258 |
$this->form['tests'][$i]['arg'] = $header; |
|
259 |
} |
|
260 |
else |
|
261 |
{ |
|
262 |
$this->form['tests'][$i]['type'] = $type; |
|
263 |
$this->form['tests'][$i]['test'] = 'header'; |
|
264 |
$this->form['tests'][$i]['arg1'] = $header; |
|
265 |
$this->form['tests'][$i]['arg2'] = $target; |
|
266 |
|
|
267 |
if ($target == '') |
|
268 |
$this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty'); |
|
269 |
} |
|
270 |
} |
|
271 |
else |
|
272 |
switch ($header) |
|
273 |
{ |
|
274 |
case 'size': |
|
275 |
$sizeop = $this->strip_value($sizeops[$idx]); |
|
276 |
$sizeitem = $this->strip_value($items[$idx]); |
|
277 |
$sizetarget = $this->strip_value($sizetargets[$idx]); |
|
278 |
|
|
279 |
$this->form['tests'][$i]['test'] = 'size'; |
|
280 |
$this->form['tests'][$i]['type'] = $sizeop; |
|
281 |
$this->form['tests'][$i]['arg'] = $sizetarget.$sizeitem; |
|
282 |
|
|
283 |
if (!preg_match('/^[0-9]+(K|M|G)*$/i', $sizetarget)) |
|
284 |
$this->errors['tests'][$i]['sizetarget'] = $this->gettext('wrongformat'); |
|
285 |
break; |
|
286 |
case '...': |
732846
|
287 |
$cust_header = $headers = $this->strip_value($cust_headers[$idx]); |
a393c3
|
288 |
|
A |
289 |
if(preg_match('/^not/', $op)) |
|
290 |
$this->form['tests'][$i]['not'] = true; |
|
291 |
$type = preg_replace('/^not/', '', $op); |
|
292 |
|
|
293 |
if ($cust_header == '') |
|
294 |
$this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); |
732846
|
295 |
else { |
A |
296 |
$headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY); |
|
297 |
|
|
298 |
if (!count($headers)) |
|
299 |
$this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); |
|
300 |
else { |
|
301 |
foreach ($headers as $hr) |
|
302 |
if (!preg_match('/^[a-z0-9-]+$/i', $hr)) |
|
303 |
$this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars'); |
36e526
|
304 |
} |
732846
|
305 |
} |
A |
306 |
|
|
307 |
if (empty($this->errors['tests'][$i]['header'])) |
36e526
|
308 |
$cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers; |
732846
|
309 |
|
A |
310 |
if ($type == 'exists') |
a393c3
|
311 |
{ |
A |
312 |
$this->form['tests'][$i]['test'] = 'exists'; |
|
313 |
$this->form['tests'][$i]['arg'] = $cust_header; |
|
314 |
} |
|
315 |
else |
|
316 |
{ |
|
317 |
$this->form['tests'][$i]['test'] = 'header'; |
|
318 |
$this->form['tests'][$i]['type'] = $type; |
|
319 |
$this->form['tests'][$i]['arg1'] = $cust_header; |
|
320 |
$this->form['tests'][$i]['arg2'] = $target; |
|
321 |
|
|
322 |
if ($target == '') |
|
323 |
$this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty'); |
|
324 |
} |
|
325 |
break; |
|
326 |
} |
|
327 |
$i++; |
|
328 |
} |
|
329 |
|
|
330 |
$i = 0; |
|
331 |
// actions |
|
332 |
foreach($act_types as $idx => $type) |
|
333 |
{ |
|
334 |
$type = $this->strip_value($type); |
|
335 |
$target = $this->strip_value($act_targets[$idx]); |
|
336 |
|
|
337 |
$this->form['actions'][$i]['type'] = $type; |
|
338 |
|
|
339 |
switch ($type) |
|
340 |
{ |
|
341 |
case 'fileinto': |
|
342 |
$mailbox = $this->strip_value($mailboxes[$idx]); |
|
343 |
$this->form['actions'][$i]['target'] = $mailbox; |
|
344 |
break; |
|
345 |
case 'reject': |
|
346 |
case 'ereject': |
|
347 |
$target = $this->strip_value($area_targets[$idx]); |
|
348 |
$this->form['actions'][$i]['target'] = str_replace("\r\n", "\n", $target); |
|
349 |
|
|
350 |
// if ($target == '') |
|
351 |
// $this->errors['actions'][$i]['targetarea'] = $this->gettext('cannotbeempty'); |
|
352 |
break; |
|
353 |
case 'redirect': |
|
354 |
$this->form['actions'][$i]['target'] = $target; |
|
355 |
|
|
356 |
if ($this->form['actions'][$i]['target'] == '') |
|
357 |
$this->errors['actions'][$i]['target'] = $this->gettext('cannotbeempty'); |
1e487a
|
358 |
else if (!$this->check_email($this->form['actions'][$i]['target'])) |
a393c3
|
359 |
$this->errors['actions'][$i]['target'] = $this->gettext('noemailwarning'); |
A |
360 |
break; |
|
361 |
case 'vacation': |
|
362 |
$reason = $this->strip_value($reasons[$idx]); |
|
363 |
$this->form['actions'][$i]['reason'] = str_replace("\r\n", "\n", $reason); |
|
364 |
$this->form['actions'][$i]['days'] = $days[$idx]; |
|
365 |
$this->form['actions'][$i]['addresses'] = explode(',', $addresses[$idx]); |
|
366 |
// @TODO: vacation :subject, :mime, :from, :handle |
|
367 |
|
|
368 |
if ($this->form['actions'][$i]['addresses']) { |
|
369 |
foreach($this->form['actions'][$i]['addresses'] as $aidx => $address) { |
|
370 |
$address = trim($address); |
|
371 |
if (!$address) |
|
372 |
unset($this->form['actions'][$i]['addresses'][$aidx]); |
1e487a
|
373 |
else if(!$this->check_email($address)) { |
a393c3
|
374 |
$this->errors['actions'][$i]['addresses'] = $this->gettext('noemailwarning'); |
A |
375 |
break; |
|
376 |
} else |
|
377 |
$this->form['actions'][$i]['addresses'][$aidx] = $address; |
|
378 |
} |
|
379 |
} |
|
380 |
|
|
381 |
if ($this->form['actions'][$i]['reason'] == '') |
|
382 |
$this->errors['actions'][$i]['reason'] = $this->gettext('cannotbeempty'); |
|
383 |
if ($this->form['actions'][$i]['days'] && !preg_match('/^[0-9]+$/', $this->form['actions'][$i]['days'])) |
|
384 |
$this->errors['actions'][$i]['days'] = $this->gettext('forbiddenchars'); |
|
385 |
break; |
|
386 |
} |
|
387 |
|
|
388 |
$i++; |
|
389 |
} |
|
390 |
|
|
391 |
if (!$this->errors) |
|
392 |
{ |
|
393 |
// zapis skryptu |
|
394 |
if (!isset($this->script[$fid])) { |
|
395 |
$fid = $this->sieve->script->add_rule($this->form); |
|
396 |
$new = true; |
|
397 |
} else |
|
398 |
$fid = $this->sieve->script->update_rule($fid, $this->form); |
|
399 |
|
|
400 |
if ($fid !== false) |
|
401 |
$save = $this->sieve->save(); |
|
402 |
|
|
403 |
if ($save && $fid !== false) |
|
404 |
{ |
|
405 |
$this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); |
|
406 |
$this->rc->output->add_script(sprintf("rcmail.managesieve_updatelist('%s', '%s', %d);", |
|
407 |
isset($new) ? 'add' : 'update', $this->form['name'], $fid), 'foot'); |
|
408 |
// $this->rc->output->command('managesieve_updatelist', isset($new) ? 'add' : 'update', $this->form['name'], $fid); |
|
409 |
// $this->rc->output->send(); |
|
410 |
} |
|
411 |
else |
|
412 |
{ |
|
413 |
$this->rc->output->show_message('managesieve.filtersaveerror', 'error'); |
|
414 |
// $this->rc->output->send(); |
|
415 |
} |
|
416 |
} |
|
417 |
} |
|
418 |
|
|
419 |
$this->managesieve_send(); |
|
420 |
} |
|
421 |
|
|
422 |
private function managesieve_send() |
|
423 |
{ |
|
424 |
// Handle form action |
|
425 |
if (isset($_GET['_framed']) || isset($_POST['_framed'])) |
|
426 |
$this->rc->output->send('managesieve.managesieveedit'); |
|
427 |
else { |
|
428 |
$this->rc->output->set_pagetitle($this->gettext('filters')); |
|
429 |
$this->rc->output->send('managesieve.managesieve'); |
|
430 |
} |
|
431 |
} |
|
432 |
|
|
433 |
// return the filters list as HTML table |
|
434 |
function filters_list($attrib) |
|
435 |
{ |
|
436 |
// add id to message list table if not specified |
|
437 |
if (!strlen($attrib['id'])) |
|
438 |
$attrib['id'] = 'rcmfilterslist'; |
|
439 |
|
|
440 |
// define list of cols to be displayed |
|
441 |
$a_show_cols = array('managesieve.filtername'); |
|
442 |
|
|
443 |
foreach($this->script as $idx => $filter) |
|
444 |
$result[] = array('managesieve.filtername' => $filter['name'], 'id' => $idx); |
|
445 |
|
|
446 |
// create XHTML table |
|
447 |
$out = rcube_table_output($attrib, $result, $a_show_cols, 'id'); |
|
448 |
|
|
449 |
// set client env |
|
450 |
$this->rc->output->add_gui_object('filterslist', $attrib['id']); |
|
451 |
$this->rc->output->include_script('list.js'); |
|
452 |
|
|
453 |
// add some labels to client |
|
454 |
$this->rc->output->add_label('managesieve.filterconfirmdelete'); |
|
455 |
|
|
456 |
return $out; |
|
457 |
} |
|
458 |
|
|
459 |
function filter_frame($attrib) |
|
460 |
{ |
|
461 |
if (!$attrib['id']) |
|
462 |
$attrib['id'] = 'rcmfilterframe'; |
|
463 |
|
|
464 |
$attrib['name'] = $attrib['id']; |
|
465 |
|
|
466 |
$this->rc->output->set_env('contentframe', $attrib['name']); |
|
467 |
$this->rc->output->set_env('blankpage', $attrib['src'] ? |
|
468 |
$this->rc->output->abs_url($attrib['src']) : 'program/blank.gif'); |
|
469 |
|
|
470 |
return html::tag('iframe', $attrib); |
|
471 |
} |
|
472 |
|
|
473 |
|
|
474 |
function filter_form($attrib) |
|
475 |
{ |
|
476 |
if (!$attrib['id']) |
|
477 |
$attrib['id'] = 'rcmfilterform'; |
|
478 |
|
|
479 |
$fid = get_input_value('_fid', RCUBE_INPUT_GPC); |
|
480 |
$scr = isset($this->form) ? $this->form : $this->script[$fid]; |
|
481 |
|
|
482 |
$hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task)); |
|
483 |
$hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save')); |
|
484 |
$hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0))); |
|
485 |
$hiddenfields->add(array('name' => '_fid', 'value' => $fid)); |
|
486 |
|
|
487 |
$out = '<form name="filterform" action="./" method="post">'."\n"; |
|
488 |
$out .= $hiddenfields->show(); |
|
489 |
|
|
490 |
// 'any' flag |
|
491 |
if (sizeof($scr['tests']) == 1 && $scr['tests'][0]['test'] == 'true' && !$scr['tests'][0]['not']) |
|
492 |
$any = true; |
|
493 |
|
|
494 |
// filter name input |
|
495 |
$field_id = '_name'; |
|
496 |
$input_name = new html_inputfield(array('name' => '_name', 'id' => $field_id, 'size' => 30, |
|
497 |
'class' => ($this->errors['name'] ? 'error' : ''))); |
|
498 |
|
|
499 |
if (isset($scr)) |
|
500 |
$input_name = $input_name->show($scr['name']); |
|
501 |
else |
|
502 |
$input_name = $input_name->show(); |
|
503 |
|
|
504 |
$out .= sprintf("\n<label for=\"%s\"><b>%s:</b></label> %s<br /><br />\n", |
|
505 |
$field_id, Q($this->gettext('filtername')), $input_name); |
|
506 |
|
|
507 |
$out .= '<fieldset><legend>' . Q($this->gettext('messagesrules')) . "</legend>\n"; |
|
508 |
|
|
509 |
// any, allof, anyof radio buttons |
|
510 |
$field_id = '_allof'; |
|
511 |
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'allof', |
|
512 |
'onclick' => 'rule_join_radio(\'allof\')', 'class' => 'radio')); |
|
513 |
|
|
514 |
if (isset($scr) && !$any) |
|
515 |
$input_join = $input_join->show($scr['join'] ? 'allof' : ''); |
|
516 |
else |
|
517 |
$input_join = $input_join->show(); |
|
518 |
|
|
519 |
$out .= sprintf("%s<label for=\"%s\">%s</label> \n", |
|
520 |
$input_join, $field_id, Q($this->gettext('filterallof'))); |
|
521 |
|
|
522 |
$field_id = '_anyof'; |
|
523 |
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'anyof', |
|
524 |
'onclick' => 'rule_join_radio(\'anyof\')', 'class' => 'radio')); |
|
525 |
|
|
526 |
if (isset($scr) && !$any) |
|
527 |
$input_join = $input_join->show($scr['join'] ? '' : 'anyof'); |
|
528 |
else |
|
529 |
$input_join = $input_join->show('anyof'); // default |
|
530 |
|
|
531 |
$out .= sprintf("%s<label for=\"%s\">%s</label>\n", |
|
532 |
$input_join, $field_id, Q($this->gettext('filteranyof'))); |
|
533 |
|
|
534 |
$field_id = '_any'; |
|
535 |
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'any', |
|
536 |
'onclick' => 'rule_join_radio(\'any\')', 'class' => 'radio')); |
|
537 |
|
|
538 |
$input_join = $input_join->show($any ? 'any' : ''); |
|
539 |
|
|
540 |
$out .= sprintf("%s<label for=\"%s\">%s</label>\n", |
|
541 |
$input_join, $field_id, Q($this->gettext('filterany'))); |
|
542 |
|
|
543 |
$rows_num = isset($scr) ? sizeof($scr['tests']) : 1; |
|
544 |
|
|
545 |
$out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>'; |
|
546 |
for ($x=0; $x<$rows_num; $x++) |
|
547 |
$out .= $this->rule_div($fid, $x); |
|
548 |
$out .= "</div>\n"; |
|
549 |
|
|
550 |
$out .= "</fieldset>\n"; |
|
551 |
|
|
552 |
// actions |
|
553 |
$out .= '<fieldset><legend>' . Q($this->gettext('messagesactions')) . "</legend>\n"; |
|
554 |
|
|
555 |
$rows_num = isset($scr) ? sizeof($scr['actions']) : 1; |
|
556 |
|
|
557 |
$out .= '<div id="actions">'; |
|
558 |
for ($x=0; $x<$rows_num; $x++) |
|
559 |
$out .= $this->action_div($fid, $x); |
|
560 |
$out .= "</div>\n"; |
|
561 |
|
|
562 |
$out .= "</fieldset>\n"; |
|
563 |
|
|
564 |
$this->rc->output->add_label('managesieve.ruledeleteconfirm'); |
|
565 |
$this->rc->output->add_label('managesieve.actiondeleteconfirm'); |
|
566 |
$this->rc->output->add_gui_object('sieveform', 'filterform'); |
|
567 |
|
|
568 |
return $out; |
|
569 |
} |
|
570 |
|
|
571 |
function rule_div($fid, $id, $div=true) |
|
572 |
{ |
|
573 |
$rule = isset($this->form) ? $this->form['tests'][$id] : $this->script[$fid]['tests'][$id]; |
|
574 |
$rows_num = isset($this->form) ? sizeof($this->form['tests']) : sizeof($this->script[$fid]['tests']); |
|
575 |
|
|
576 |
$out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : ''; |
|
577 |
|
|
578 |
$out .= '<table><tr><td class="rowactions">'; |
|
579 |
|
|
580 |
// headers select |
|
581 |
$select_header = new html_select(array('name' => "_header[]", 'id' => 'header'.$id, |
|
582 |
'onchange' => 'header_select(' .$id .')')); |
|
583 |
foreach($this->headers as $name => $val) |
|
584 |
$select_header->add(Q($this->gettext($name)), Q($val)); |
|
585 |
$select_header->add(Q($this->gettext('size')), 'size'); |
|
586 |
$select_header->add(Q($this->gettext('...')), '...'); |
|
587 |
|
|
588 |
// TODO: list arguments |
|
589 |
|
732846
|
590 |
if ((isset($rule['test']) && $rule['test'] == 'header') |
A |
591 |
&& !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers)) |
a393c3
|
592 |
$out .= $select_header->show($rule['arg1']); |
732846
|
593 |
elseif ((isset($rule['test']) && $rule['test'] == 'exists') |
A |
594 |
&& !is_array($rule['arg']) && in_array($rule['arg'], $this->headers)) |
a393c3
|
595 |
$out .= $select_header->show($rule['arg']); |
A |
596 |
elseif (isset($rule['test']) && $rule['test'] == 'size') |
|
597 |
$out .= $select_header->show('size'); |
|
598 |
elseif (isset($rule['test']) && $rule['test'] != 'true') |
|
599 |
$out .= $select_header->show('...'); |
|
600 |
else |
|
601 |
$out .= $select_header->show(); |
|
602 |
|
|
603 |
$out .= '</td><td class="rowtargets">'; |
|
604 |
|
732846
|
605 |
if ((isset($rule['test']) && $rule['test'] == 'header') |
A |
606 |
&& (is_array($rule['arg1']) || !in_array($rule['arg1'], $this->headers))) |
|
607 |
$custom = is_array($rule['arg1']) ? implode(', ', $rule['arg1']) : $rule['arg1']; |
|
608 |
elseif ((isset($rule['test']) && $rule['test'] == 'exists') |
|
609 |
&& (is_array($rule['arg']) || !in_array($rule['arg'], $this->headers))) |
|
610 |
$custom = is_array($rule['arg']) ? implode(', ', $rule['arg']) : $rule['arg']; |
a393c3
|
611 |
|
A |
612 |
$out .= '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '"> |
|
613 |
<input type="text" name="_custom_header[]" '. $this->error_class($id, 'test', 'header') |
|
614 |
.' value="' .Q($custom). '" size="20" /> </div>' . "\n"; |
|
615 |
|
|
616 |
// matching type select (operator) |
|
617 |
$select_op = new html_select(array('name' => "_rule_op[]", 'id' => 'rule_op'.$id, |
|
618 |
'style' => 'display:' .($rule['test']!='size' ? 'inline' : 'none'), 'onchange' => 'rule_op_select('.$id.')')); |
|
619 |
$select_op->add(Q($this->gettext('filtercontains')), 'contains'); |
|
620 |
$select_op->add(Q($this->gettext('filternotcontains')), 'notcontains'); |
|
621 |
$select_op->add(Q($this->gettext('filteris')), 'is'); |
|
622 |
$select_op->add(Q($this->gettext('filterisnot')), 'notis'); |
|
623 |
$select_op->add(Q($this->gettext('filterexists')), 'exists'); |
|
624 |
$select_op->add(Q($this->gettext('filternotexists')), 'notexists'); |
|
625 |
// $select_op->add(Q($this->gettext('filtermatches')), 'matches'); |
|
626 |
// $select_op->add(Q($this->gettext('filternotmatches')), 'notmatches'); |
|
627 |
|
|
628 |
// target input (TODO: lists) |
|
629 |
|
|
630 |
if ($rule['test'] == 'header') |
|
631 |
{ |
|
632 |
$out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['type']); |
|
633 |
$target = $rule['arg2']; |
|
634 |
} |
|
635 |
elseif ($rule['test'] == 'size') |
|
636 |
{ |
|
637 |
$out .= $select_op->show(); |
|
638 |
if(preg_match('/^([0-9]+)(K|M|G)*$/', $rule['arg'], $matches)) |
|
639 |
{ |
|
640 |
$sizetarget = $matches[1]; |
|
641 |
$sizeitem = $matches[2]; |
|
642 |
} |
|
643 |
} |
|
644 |
else |
|
645 |
{ |
|
646 |
$out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['test']); |
|
647 |
$target = ''; |
|
648 |
} |
|
649 |
|
|
650 |
$out .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '" |
|
651 |
value="' .Q($target). '" size="20" ' . $this->error_class($id, 'test', 'target') |
|
652 |
. ' style="display:' . ($rule['test']!='size' && $rule['test'] != 'exists' ? 'inline' : 'none') . '" />'."\n"; |
|
653 |
|
|
654 |
$select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id)); |
|
655 |
$select_size_op->add(Q($this->gettext('filterunder')), 'under'); |
|
656 |
$select_size_op->add(Q($this->gettext('filterover')), 'over'); |
|
657 |
|
|
658 |
$out .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">'; |
|
659 |
$out .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : ''); |
|
660 |
$out .= '<input type="text" name="_rule_size_target[]" value="'.$sizetarget.'" size="10" ' . $this->error_class($id, 'test', 'sizetarget') .' /> |
|
661 |
<input type="radio" name="_rule_size_item['.$id.']" value=""'. (!$sizeitem ? ' checked="checked"' : '') .' class="radio" />B |
|
662 |
<input type="radio" name="_rule_size_item['.$id.']" value="K"'. ($sizeitem=='K' ? ' checked="checked"' : '') .' class="radio" />kB |
|
663 |
<input type="radio" name="_rule_size_item['.$id.']" value="M"'. ($sizeitem=='M' ? ' checked="checked"' : '') .' class="radio" />MB |
|
664 |
<input type="radio" name="_rule_size_item['.$id.']" value="G"'. ($sizeitem=='G' ? ' checked="checked"' : '') .' class="radio" />GB'; |
|
665 |
$out .= '</div>'; |
|
666 |
$out .= '</td>'; |
|
667 |
|
|
668 |
// add/del buttons |
|
669 |
$out .= '<td class="rowbuttons">'; |
|
670 |
$out .= '<input type="button" id="ruleadd' . $id .'" value="'. Q($this->gettext('add')). '" |
|
671 |
onclick="rcmail.managesieve_ruleadd(' . $id .')" class="button" /> '; |
|
672 |
$out .= '<input type="button" id="ruledel' . $id .'" value="'. Q($this->gettext('del')). '" |
|
673 |
onclick="rcmail.managesieve_ruledel(' . $id .')" class="button' . ($rows_num<2 ? ' disabled' : '') .'"' |
|
674 |
. ($rows_num<2 ? ' disabled="disabled"' : '') .' />'; |
|
675 |
$out .= '</td></tr></table>'; |
|
676 |
|
|
677 |
$out .= $div ? "</div>\n" : ''; |
|
678 |
|
|
679 |
return $out; |
|
680 |
} |
|
681 |
|
|
682 |
function action_div($fid, $id, $div=true) |
|
683 |
{ |
|
684 |
$action = isset($this->form) ? $this->form['actions'][$id] : $this->script[$fid]['actions'][$id]; |
|
685 |
$rows_num = isset($this->form) ? sizeof($this->form['actions']) : sizeof($this->script[$fid]['actions']); |
|
686 |
|
|
687 |
$out = $div ? '<div class="actionrow" id="actionrow' .$id .'">'."\n" : ''; |
|
688 |
|
|
689 |
$out .= '<table><tr><td class="rowactions">'; |
|
690 |
|
|
691 |
// action select |
|
692 |
$select_action = new html_select(array('name' => "_action_type[]", 'id' => 'action_type'.$id, |
|
693 |
'onchange' => 'action_type_select(' .$id .')')); |
|
694 |
if (in_array('fileinto', $this->exts)) |
|
695 |
$select_action->add(Q($this->gettext('messagemoveto')), 'fileinto'); |
|
696 |
$select_action->add(Q($this->gettext('messageredirect')), 'redirect'); |
|
697 |
if (in_array('reject', $this->exts)) |
|
698 |
$select_action->add(Q($this->gettext('messagediscard')), 'reject'); |
|
699 |
elseif (in_array('ereject', $this->exts)) |
|
700 |
$select_action->add(Q($this->gettext('messagediscard')), 'ereject'); |
|
701 |
if (in_array('vacation', $this->exts)) |
|
702 |
$select_action->add(Q($this->gettext('messagereply')), 'vacation'); |
|
703 |
$select_action->add(Q($this->gettext('messagedelete')), 'discard'); |
|
704 |
$select_action->add(Q($this->gettext('rulestop')), 'stop'); |
|
705 |
|
|
706 |
$out .= $select_action->show($action['type']); |
|
707 |
$out .= '</td>'; |
|
708 |
|
|
709 |
// actions target inputs |
|
710 |
$out .= '<td class="rowtargets">'; |
|
711 |
// shared targets |
|
712 |
$out .= '<input type="text" name="_action_target[]" id="action_target' .$id. '" ' |
|
713 |
.'value="' .($action['type']=='redirect' ? Q($action['target'], 'strict', false) : ''). '" size="40" ' |
|
714 |
.'style="display:' .($action['type']=='redirect' ? 'inline' : 'none') .'" ' |
|
715 |
. $this->error_class($id, 'action', 'target') .' />'; |
|
716 |
$out .= '<textarea name="_action_target_area[]" id="action_target_area' .$id. '" ' |
|
717 |
.'rows="3" cols="40" '. $this->error_class($id, 'action', 'targetarea') |
|
718 |
.'style="display:' .(in_array($action['type'], array('reject', 'ereject')) ? 'inline' : 'none') .'">' |
|
719 |
. (in_array($action['type'], array('reject', 'ereject')) ? Q($action['target'], 'strict', false) : '') |
|
720 |
. "</textarea>\n"; |
|
721 |
|
|
722 |
// vacation |
|
723 |
$out .= '<div id="action_vacation' .$id.'" style="display:' .($action['type']=='vacation' ? 'inline' : 'none') .'">'; |
|
724 |
$out .= '<span class="label">'. Q($this->gettext('vacationreason')) .'</span><br />' |
|
725 |
.'<textarea name="_action_reason[]" id="action_reason' .$id. '" ' |
|
726 |
.'rows="3" cols="40" '. $this->error_class($id, 'action', 'reason') . '>' |
|
727 |
. Q($action['reason'], 'strict', false) . "</textarea>\n"; |
|
728 |
$out .= '<br /><span class="label">' .Q($this->gettext('vacationaddresses')) . '</span><br />' |
|
729 |
.'<input type="text" name="_action_addresses[]" ' |
|
730 |
.'value="' . (is_array($action['addresses']) ? Q(implode(', ', $action['addresses']), 'strict', false) : $action['addresses']) . '" size="40" ' |
|
731 |
. $this->error_class($id, 'action', 'addresses') .' />'; |
|
732 |
$out .= '<br /><span class="label">' . Q($this->gettext('vacationdays')) . '</span><br />' |
|
733 |
.'<input type="text" name="_action_days[]" ' |
|
734 |
.'value="' .Q($action['days'], 'strict', false) . '" size="2" ' |
|
735 |
. $this->error_class($id, 'action', 'days') .' />'; |
|
736 |
$out .= '</div>'; |
|
737 |
|
|
738 |
// mailbox select |
|
739 |
$out .= '<select id="action_mailbox' .$id. '" name="_action_mailbox[]" style="display:' |
|
740 |
.(!isset($action) || $action['type']=='fileinto' ? 'inline' : 'none'). '">'; |
|
741 |
|
|
742 |
$this->rc->imap_init(true); |
|
743 |
|
|
744 |
$a_folders = $this->rc->imap->list_mailboxes(); |
|
745 |
$delimiter = $this->rc->imap->get_hierarchy_delimiter(); |
|
746 |
|
36969e
|
747 |
// set mbox encoding |
A |
748 |
$mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP'); |
|
749 |
|
a393c3
|
750 |
if ($action['type'] == 'fileinto') |
A |
751 |
$mailbox = $action['target']; |
|
752 |
else |
|
753 |
$mailbox = ''; |
|
754 |
|
|
755 |
foreach ($a_folders as $folder) |
|
756 |
{ |
8eb424
|
757 |
$utf7folder = $this->rc->imap->mod_mailbox($folder); |
a393c3
|
758 |
$names = explode($delimiter, rcube_charset_convert($folder, 'UTF7-IMAP')); |
A |
759 |
$name = $names[sizeof($names)-1]; |
|
760 |
|
|
761 |
if ($replace_delimiter = $this->rc->config->get('managesieve_replace_delimiter')) |
|
762 |
$utf7folder = str_replace($delimiter, $replace_delimiter, $utf7folder); |
36969e
|
763 |
|
A |
764 |
// convert to Sieve implementation encoding |
|
765 |
$utf7folder = $this->mbox_encode($utf7folder, $mbox_encoding); |
a393c3
|
766 |
|
A |
767 |
if ($folder_class = rcmail_folder_classname($name)) |
|
768 |
$foldername = $this->gettext($folder_class); |
|
769 |
else |
|
770 |
$foldername = $name; |
|
771 |
|
|
772 |
$out .= sprintf('<option value="%s"%s>%s%s</option>'."\n", |
|
773 |
htmlspecialchars($utf7folder), |
|
774 |
($mailbox == $utf7folder ? ' selected="selected"' : ''), |
|
775 |
str_repeat(' ', 4 * (sizeof($names)-1)), |
|
776 |
Q(abbreviate_string($foldername, 40 - (2 * sizeof($names)-1)))); |
|
777 |
} |
|
778 |
$out .= '</select>'; |
|
779 |
$out .= '</td>'; |
|
780 |
|
|
781 |
// add/del buttons |
|
782 |
$out .= '<td class="rowbuttons">'; |
|
783 |
$out .= '<input type="button" id="actionadd' . $id .'" value="'. Q($this->gettext('add')). '" |
|
784 |
onclick="rcmail.managesieve_actionadd(' . $id .')" class="button" /> '; |
|
785 |
$out .= '<input type="button" id="actiondel' . $id .'" value="'. Q($this->gettext('del')). '" |
|
786 |
onclick="rcmail.managesieve_actiondel(' . $id .')" class="button' . ($rows_num<2 ? ' disabled' : '') .'"' |
|
787 |
. ($rows_num<2 ? ' disabled="disabled"' : '') .' />'; |
|
788 |
$out .= '</td>'; |
|
789 |
|
|
790 |
$out .= '</tr></table>'; |
|
791 |
|
|
792 |
$out .= $div ? "</div>\n" : ''; |
|
793 |
|
|
794 |
return $out; |
|
795 |
} |
|
796 |
|
|
797 |
private function genid() |
|
798 |
{ |
|
799 |
$result = intval(rcube_timer()); |
|
800 |
return $result; |
|
801 |
} |
|
802 |
|
|
803 |
private function strip_value($str) |
|
804 |
{ |
|
805 |
return trim(strip_tags($str)); |
|
806 |
} |
|
807 |
|
|
808 |
private function error_class($id, $type, $target, $name_only=false) |
|
809 |
{ |
|
810 |
// TODO: tooltips |
|
811 |
if ($type == 'test' && isset($this->errors['tests'][$id][$target])) |
|
812 |
return ($name_only ? 'error' : ' class="error"'); |
|
813 |
elseif ($type == 'action' && isset($this->errors['actions'][$id][$target])) |
|
814 |
return ($name_only ? 'error' : ' class="error"'); |
|
815 |
|
|
816 |
return ''; |
|
817 |
} |
|
818 |
|
|
819 |
private function check_email($email) |
|
820 |
{ |
|
821 |
// Check for invalid characters |
|
822 |
if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) |
|
823 |
return false; |
|
824 |
|
|
825 |
// Check that there's one @ symbol, and that the lengths are right |
|
826 |
if (!preg_match('/^[^@]{1,64}@[^@]{1,255}$/', $email)) |
|
827 |
return false; |
|
828 |
|
|
829 |
// Split it into sections to make life easier |
|
830 |
$email_array = explode('@', $email); |
|
831 |
|
|
832 |
// Check local part |
|
833 |
$local_array = explode('.', $email_array[0]); |
|
834 |
foreach ($local_array as $local_part) |
|
835 |
if (!preg_match('/^(([A-Za-z0-9!#$%&\'*+\/=?^_`{|}~-]+)|("[^"]+"))$/', $local_part)) |
|
836 |
return false; |
|
837 |
|
|
838 |
// Check domain part |
|
839 |
if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/', $email_array[1]) |
|
840 |
|| preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/', $email_array[1])) |
|
841 |
return true; // If an IP address |
|
842 |
else |
|
843 |
{ // If not an IP address |
|
844 |
$domain_array = explode('.', $email_array[1]); |
|
845 |
if (sizeof($domain_array) < 2) |
|
846 |
return false; // Not enough parts to be a valid domain |
|
847 |
|
|
848 |
foreach ($domain_array as $domain_part) |
|
849 |
if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $domain_part)) |
|
850 |
return false; |
|
851 |
|
|
852 |
return true; |
|
853 |
} |
|
854 |
|
|
855 |
return false; |
|
856 |
} |
|
857 |
|
36969e
|
858 |
private function mbox_encode($text, $encoding) |
A |
859 |
{ |
|
860 |
return rcube_charset_convert($text, 'UTF7-IMAP', $encoding); |
|
861 |
} |
a393c3
|
862 |
} |
A |
863 |
|
|
864 |
?> |