Overview

Packages

  • Horde
    • Icalendar
      • UnitTests
  • Ingo
    • UnitTests
  • None

Classes

  • Horde_Core_Ui_VarRenderer_Ingo
  • Ingo
  • Ingo_Api
  • Ingo_Exception
  • Ingo_Exception_Pear
  • Ingo_LoginTasks_SystemTask_Upgrade
  • Ingo_Script
  • Ingo_Script_Imap
  • Ingo_Script_Imap_Api
  • Ingo_Script_Imap_Live
  • Ingo_Script_Maildrop
  • Ingo_Script_Maildrop_Comment
  • Ingo_Script_Maildrop_Recipe
  • Ingo_Script_Maildrop_Variable
  • Ingo_Script_Procmail
  • Ingo_Script_Procmail_Comment
  • Ingo_Script_Procmail_Recipe
  • Ingo_Script_Procmail_Variable
  • Ingo_Script_Sieve
  • Ingo_Script_Sieve_Action
  • Ingo_Script_Sieve_Action_Addflag
  • Ingo_Script_Sieve_Action_Discard
  • Ingo_Script_Sieve_Action_Fileinto
  • Ingo_Script_Sieve_Action_Flag
  • Ingo_Script_Sieve_Action_Keep
  • Ingo_Script_Sieve_Action_Notify
  • Ingo_Script_Sieve_Action_Redirect
  • Ingo_Script_Sieve_Action_Reject
  • Ingo_Script_Sieve_Action_Removeflag
  • Ingo_Script_Sieve_Action_Stop
  • Ingo_Script_Sieve_Action_Vacation
  • Ingo_Script_Sieve_Comment
  • Ingo_Script_Sieve_Else
  • Ingo_Script_Sieve_Elsif
  • Ingo_Script_Sieve_If
  • Ingo_Script_Sieve_Test
  • Ingo_Script_Sieve_Test_Address
  • Ingo_Script_Sieve_Test_Allof
  • Ingo_Script_Sieve_Test_Anyof
  • Ingo_Script_Sieve_Test_Body
  • Ingo_Script_Sieve_Test_Exists
  • Ingo_Script_Sieve_Test_False
  • Ingo_Script_Sieve_Test_Header
  • Ingo_Script_Sieve_Test_Not
  • Ingo_Script_Sieve_Test_Relational
  • Ingo_Script_Sieve_Test_Size
  • Ingo_Script_Sieve_Test_True
  • Ingo_Storage
  • Ingo_Storage_Blacklist
  • Ingo_Storage_Filters
  • Ingo_Storage_Filters_Sql
  • Ingo_Storage_Forward
  • Ingo_Storage_Mock
  • Ingo_Storage_Prefs
  • Ingo_Storage_Rule
  • Ingo_Storage_Spam
  • Ingo_Storage_Sql
  • Ingo_Storage_Vacation
  • Ingo_Storage_VacationTest
  • Ingo_Storage_Whitelist
  • Ingo_Test
  • Ingo_Transport
  • Ingo_Transport_Ldap
  • Ingo_Transport_Null
  • Ingo_Transport_Sivtest
  • Ingo_Transport_Timsieved
  • Ingo_Transport_Vfs
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Ingo_Script_Sieve class represents a Sieve Script.
  4:  *
  5:  * See the enclosed file LICENSE for license information (ASL).  If you
  6:  * did not receive this file, see http://www.horde.org/licenses/apache.
  7:  *
  8:  * @author  Mike Cochrane <mike@graftonhall.co.nz>
  9:  * @package Ingo
 10:  */
 11: class Ingo_Script_Sieve extends Ingo_Script
 12: {
 13:     /**
 14:      * The list of actions allowed (implemented) for this driver.
 15:      *
 16:      * @var array
 17:      */
 18:     protected $_actions = array(
 19:         Ingo_Storage::ACTION_KEEP,
 20:         Ingo_Storage::ACTION_MOVE,
 21:         Ingo_Storage::ACTION_DISCARD,
 22:         Ingo_Storage::ACTION_REDIRECT,
 23:         Ingo_Storage::ACTION_REDIRECTKEEP,
 24:         Ingo_Storage::ACTION_MOVEKEEP,
 25:         Ingo_Storage::ACTION_REJECT,
 26:         Ingo_Storage::ACTION_FLAGONLY,
 27:         Ingo_Storage::ACTION_NOTIFY
 28:     );
 29: 
 30:     /**
 31:      * The categories of filtering allowed.
 32:      *
 33:      * @var array
 34:      */
 35:     protected $_categories = array(
 36:         Ingo_Storage::ACTION_BLACKLIST,
 37:         Ingo_Storage::ACTION_WHITELIST,
 38:         Ingo_Storage::ACTION_VACATION,
 39:         Ingo_Storage::ACTION_FORWARD,
 40:         Ingo_Storage::ACTION_SPAM
 41:     );
 42: 
 43:     /**
 44:      * The list of tests allowed (implemented) for this driver.
 45:      *
 46:      * @var array
 47:      */
 48:     protected $_tests = array(
 49:         'contains',
 50:         'not contain',
 51:         'is',
 52:         'not is',
 53:         'begins with',
 54:         'not begins with',
 55:         'ends with',
 56:         'not ends with',
 57:         'exists',
 58:         'not exist',
 59:         'less than',
 60:         'less than or equal to',
 61:         'equal',
 62:         'not equal',
 63:         'greater than',
 64:         'greater than or equal to',
 65:         'regex',
 66:         'matches',
 67:         'not matches'
 68:     );
 69: 
 70:     /**
 71:      * The types of tests allowed (implemented) for this driver.
 72:      *
 73:      * @var array
 74:      */
 75:     protected $_types = array(
 76:         Ingo_Storage::TYPE_HEADER,
 77:         Ingo_Storage::TYPE_SIZE,
 78:         Ingo_Storage::TYPE_BODY
 79:     );
 80: 
 81:     /**
 82:      * Can tests be case sensitive?
 83:      *
 84:      * @var boolean
 85:      */
 86:     protected $_casesensitive = true;
 87: 
 88:     /**
 89:      * Does the driver support setting IMAP flags?
 90:      *
 91:      * @var boolean
 92:      */
 93:     protected $_supportIMAPFlags = true;
 94: 
 95:     /**
 96:      * Does the driver support the stop-script option?
 97:      *
 98:      * @var boolean
 99:      */
100:     protected $_supportStopScript = true;
101: 
102:     /**
103:      * Does the driver require a script file to be generated?
104:      *
105:      * @var boolean
106:      */
107:     protected $_scriptfile = true;
108: 
109:     /**
110:      * The blocks that make up the code.
111:      *
112:      * @var array
113:      */
114:     protected $_blocks = array();
115: 
116:     /**
117:      * The blocks that have to appear at the end of the code.
118:      *
119:      * @var array
120:      */
121:     protected $_endBlocks = array();
122: 
123:     /**
124:      * Returns a script previously generated with generate().
125:      *
126:      * @return string  The Sieve script.
127:      */
128:     public function toCode()
129:     {
130:         $code = "# Sieve Filter\n# "
131:             . _("Generated by Ingo (http://www.horde.org/ingo/)") . ' ('
132:             . trim(strftime($this->_params['date_format'] . ', ' . $this->_params['time_format']))
133:             . ")\n\n";
134:         $requires = $this->requires();
135: 
136:         if (count($requires) > 1) {
137:             $stringlist = '';
138:             foreach ($this->requires() as $require) {
139:                 $stringlist .= (empty($stringlist)) ? '"' : ', "';
140:                 $stringlist .= $require . '"';
141:             }
142:             $code .= 'require [' . $stringlist . '];' . "\n\n";
143:         } elseif (count($requires) == 1) {
144:             foreach ($this->requires() as $require) {
145:                 $code .= 'require "' . $require . '";' . "\n\n";
146:             }
147:         }
148: 
149:         foreach ($this->_blocks as $block) {
150:             $code .= $block->toCode() . "\n";
151:         }
152: 
153:         return rtrim($code) . "\n";
154:     }
155: 
156:     /**
157:      * Escape a string according to Sieve RFC 3028 [2.4.2].
158:      *
159:      * @param string $string      The string to escape.
160:      * @param boolean $regexmode  Is the escaped string a regex value?
161:      *                            Defaults to no.
162:      *
163:      * @return string  The escaped string.
164:      */
165:     static public function escapeString($string, $regexmode = false)
166:     {
167:         /* Remove any backslashes in front of commas. */
168:         $string = str_replace('\,', ',', $string);
169: 
170:         return $regexmode
171:             ? str_replace('"', addslashes('"'), $string)
172:             : str_replace(array('\\', '"'), array(addslashes('\\'), addslashes('"')), $string);
173:     }
174: 
175:     /**
176:      * Checks if all rules are valid.
177:      *
178:      * @return boolean|string  True if all rules are valid, an error message
179:      *                         otherwise.
180:      */
181:     public function check()
182:     {
183:         foreach ($this->_blocks as $block) {
184:             $res = $block->check();
185:             if ($res !== true) {
186:                 return $res;
187:             }
188:         }
189: 
190:         return true;
191:     }
192: 
193:     /**
194:      * Returns a list of sieve extensions required for this rule and any
195:      * sub-rules.
196:      *
197:      * @return array  A Sieve extension list.
198:      */
199:     public function requires()
200:     {
201:         $requires = array();
202:         foreach ($this->_blocks as $block) {
203:             $requires = array_merge($requires, $block->requires());
204:         }
205: 
206:         return array_unique($requires);
207:     }
208: 
209:     /**
210:      * Adds all blocks necessary for the forward rule.
211:      */
212:     protected function _addForwardBlocks()
213:     {
214:         if (!$this->_validRule(Ingo_Storage::ACTION_FORWARD)) {
215:             return;
216:         }
217: 
218:         $forward = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_FORWARD);
219:         $fwd_addr = $forward->getForwardAddresses();
220:         if (empty($fwd_addr)) {
221:             return;
222:         }
223: 
224:         $action = array();
225:         foreach ($fwd_addr as $addr) {
226:             $addr = trim($addr);
227:             if (!empty($addr)) {
228:                 $action[] = new Ingo_Script_Sieve_Action_Redirect(array('address' => $addr));
229:             }
230:         }
231: 
232:         if (count($action)) {
233:             if($forward->getForwardKeep()) {
234:                 $this->_endBlocks[] = new Ingo_Script_Sieve_Comment(_("Forward Keep Action"));
235:                 $if = new Ingo_Script_Sieve_If(new Ingo_Script_Sieve_Test_True());
236:                 $if->setActions(array(new Ingo_Script_Sieve_Action_Keep(),
237:                                       new Ingo_Script_Sieve_Action_Stop()));
238:                 $this->_endBlocks[] = $if;
239:             } else {
240:                 $action[] = new Ingo_Script_Sieve_Action_Stop();
241:             }
242:         }
243: 
244:         $this->_blocks[] = new Ingo_Script_Sieve_Comment(_("Forwards"));
245: 
246:         $test = new Ingo_Script_Sieve_Test_True();
247:         $if = new Ingo_Script_Sieve_If($test);
248:         $if->setActions($action);
249:         $this->_blocks[] = $if;
250:     }
251: 
252:     /**
253:      * Adds all blocks necessary for the blacklist rule.
254:      */
255:     protected function _addBlacklistBlocks()
256:     {
257:         if (!$this->_validRule(Ingo_Storage::ACTION_BLACKLIST)) {
258:             return;
259:         }
260: 
261:         $blacklist = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_BLACKLIST);
262:         $bl_addr = $blacklist->getBlacklist();
263:         $folder = $blacklist->getBlacklistFolder();
264:         if (empty($bl_addr)) {
265:             return;
266:         }
267: 
268:         $action = array();
269:         if (empty($folder)) {
270:             $action[] = new Ingo_Script_Sieve_Action_Discard();
271:         } elseif ($folder == Ingo::BLACKLIST_MARKER) {
272:             $action[] = new Ingo_Script_Sieve_Action_Addflag(array('flags' => Ingo_Storage::FLAG_DELETED));
273:             $action[] = new Ingo_Script_Sieve_Action_Keep();
274:             $action[] = new Ingo_Script_Sieve_Action_Removeflag(array('flags' => Ingo_Storage::FLAG_DELETED));
275:         } else {
276:             $action[] = new Ingo_Script_Sieve_Action_Fileinto(array_merge($this->_params, array('folder' => $folder)));
277:         }
278: 
279:         $action[] = new Ingo_Script_Sieve_Action_Stop();
280: 
281:         $this->_blocks[] = new Ingo_Script_Sieve_Comment(_("Blacklisted Addresses"));
282: 
283:         /* Split the test up to only do 5 addresses at a time. */
284:         $temp = array();
285:         $wildcards = array();
286:         foreach ($bl_addr as $address) {
287:             if (!empty($address)) {
288:                 if ((strstr($address, '*') !== false) ||
289:                     (strstr($address, '?') !== false)) {
290:                     $wildcards[] = $address;
291:                 } else {
292:                     $temp[] = $address;
293:                 }
294:             }
295:             if (count($temp) == 5) {
296:                 $test = new Ingo_Script_Sieve_Test_Address(array('headers' => "From\nSender\nResent-From", 'addresses' => implode("\n", $temp)));
297:                 $if = new Ingo_Script_Sieve_If($test);
298:                 $if->setActions($action);
299:                 $this->_blocks[] = $if;
300:                 $temp = array();
301:             }
302:             if (count($wildcards) == 5) {
303:                 $test = new Ingo_Script_Sieve_Test_Address(array('headers' => "From\nSender\nResent-From", 'match-type' => ':matches', 'addresses' => implode("\n", $wildcards)));
304:                 $if = new Ingo_Script_Sieve_If($test);
305:                 $if->setActions($action);
306:                 $this->_blocks[] = $if;
307:                 $wildcards = array();
308:             }
309:         }
310: 
311:         if ($temp) {
312:             $test = new Ingo_Script_Sieve_Test_Address(array('headers' => "From\nSender\nResent-From", 'addresses' => implode("\n", $temp)));
313:             $if = new Ingo_Script_Sieve_If($test);
314:             $if->setActions($action);
315:             $this->_blocks[] = $if;
316:         }
317: 
318:         if ($wildcards) {
319:             $test = new Ingo_Script_Sieve_Test_Address(array('headers' => "From\nSender\nResent-From", 'match-type' => ':matches', 'addresses' => implode("\n", $wildcards)));
320:             $if = new Ingo_Script_Sieve_If($test);
321:             $if->setActions($action);
322:             $this->_blocks[] = $if;
323:         }
324:     }
325: 
326:     /**
327:      * Adds all blocks necessary for the whitelist rule.
328:      */
329:     protected function _addWhitelistBlocks()
330:     {
331:         if (!$this->_validRule(Ingo_Storage::ACTION_WHITELIST)) {
332:             return;
333:         }
334: 
335:         $whitelist = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_WHITELIST);
336:         $wl_addr = $whitelist->getWhitelist();
337:         if (empty($wl_addr)) {
338:             return;
339:         }
340: 
341:         $this->_blocks[] = new Ingo_Script_Sieve_Comment(_("Whitelisted Addresses"));
342: 
343:         $action = array(new Ingo_Script_Sieve_Action_Keep(), new Ingo_Script_Sieve_Action_Stop());
344:         $test = new Ingo_Script_Sieve_Test_Address(array('headers' => "From\nSender\nResent-From", 'addresses' => implode("\n", $wl_addr)));
345:         $if = new Ingo_Script_Sieve_If($test);
346:         $if->setActions($action);
347:         $this->_blocks[] = $if;
348:     }
349: 
350:     /**
351:      * Adds all blocks necessary for the vacation rule.
352:      */
353:     protected function _addVacationBlocks()
354:     {
355:         if (!$this->_validRule(Ingo_Storage::ACTION_VACATION)) {
356:             return;
357:         }
358: 
359:         $vacation = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_VACATION);
360:         $vacation_addr = $vacation->getVacationAddresses();
361:         if (!count($vacation_addr)) {
362:             return;
363:         }
364: 
365:         $vals = array(
366:             'subject' => $vacation->getVacationSubject(),
367:             'days' => $vacation->getVacationDays(),
368:             'addresses' => $vacation_addr,
369:             'start' => $vacation->getVacationStart(),
370:             'start_year' => $vacation->getVacationStartYear(),
371:             'start_month' => $vacation->getVacationStartMonth(),
372:             'start_day' => $vacation->getVacationStartDay(),
373:             'end' => $vacation->getVacationEnd(),
374:             'end_year' => $vacation->getVacationEndYear(),
375:             'end_month' => $vacation->getVacationEndMonth(),
376:             'end_day' => $vacation->getVacationEndDay(),
377:             'reason' => $vacation->getVacationReason(),
378:         );
379: 
380:         $action = $tests = array();
381:         $action[] = new Ingo_Script_Sieve_Action_Vacation($vals);
382: 
383:         if ($vacation->getVacationIgnorelist()) {
384:             $mime_headers = new Horde_Mime_Headers();
385:             $headers = $mime_headers->listHeaders();
386:             $headers['Mailing-List'] = null;
387:             $tmp = new Ingo_Script_Sieve_Test_Exists(array('headers' => implode("\n", array_keys($headers))));
388:             $tests[] = new Ingo_Script_Sieve_Test_Not($tmp);
389:             $vals = array('headers' => 'Precedence',
390:                           'match-type' => ':is',
391:                           'strings' => "list\nbulk\njunk",
392:                           'comparator' => 'i;ascii-casemap');
393:             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
394:             $tests[] = new Ingo_Script_Sieve_Test_Not($tmp);
395:             $vals = array('headers' => 'To',
396:                           'match-type' => ':matches',
397:                           'strings' => 'Multiple recipients of*',
398:                           'comparator' => 'i;ascii-casemap');
399:             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
400:             $tests[] = new Ingo_Script_Sieve_Test_Not($tmp);
401:         }
402: 
403:         $addrs = array();
404:         foreach ($vacation->getVacationExcludes() as $addr) {
405:             $addr = trim($addr);
406:             if (!empty($addr)) {
407:                 $addrs[] = $addr;
408:             }
409:         }
410: 
411:         if ($addrs) {
412:             $tmp = new Ingo_Script_Sieve_Test_Address(array('headers' => "From\nSender\nResent-From", 'addresses' => implode("\n", $addrs)));
413:             $tests[] = new Ingo_Script_Sieve_Test_Not($tmp);
414:         }
415: 
416:         $this->_blocks[] = new Ingo_Script_Sieve_Comment(_("Vacation"));
417: 
418:         if ($tests) {
419:             $test = new Ingo_Script_Sieve_Test_Allof($tests);
420:             $if = new Ingo_Script_Sieve_If($test);
421:             $if->setActions($action);
422:             $this->_blocks[] = $if;
423:         } else {
424:             $this->_blocks[] = $action[0];
425:         }
426:     }
427: 
428:     /**
429:      * Adds all blocks necessary for the spam rule.
430:      */
431:     protected function _addSpamBlocks()
432:     {
433:         if (!$this->_validRule(Ingo_Storage::ACTION_SPAM)) {
434:             return;
435:         }
436: 
437:         $spam = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_SPAM);
438:         if ($spam === false) {
439:             return;
440:         }
441: 
442:         $this->_blocks[] = new Ingo_Script_Sieve_Comment(_("Spam Filter"));
443: 
444:         $actions = array();
445:         $actions[] = new Ingo_Script_Sieve_Action_Fileinto(array_merge($this->_params, array('folder' => $spam->getSpamFolder())));
446: 
447:         if ($this->_params['spam_compare'] == 'numeric') {
448:             $vals = array(
449:                 'headers' => $this->_params['spam_header'],
450:                 'comparison' => 'ge',
451:                 'value' => $spam->getSpamLevel(),
452:             );
453:             $test = new Ingo_Script_Sieve_Test_Relational($vals);
454:         } elseif ($this->_params['spam_compare'] == 'string') {
455:             $vals = array(
456:                 'headers' => $this->_params['spam_header'],
457:                 'match-type' => ':contains',
458:                 'strings' => str_repeat($this->_params['spam_char'],
459:                                         $spam->getSpamLevel()),
460:                 'comparator' => 'i;ascii-casemap',
461:             );
462:             $test = new Ingo_Script_Sieve_Test_Header($vals);
463:         }
464: 
465:         $actions[] = new Ingo_Script_Sieve_Action_Stop();
466: 
467:         $if = new Ingo_Script_Sieve_If($test);
468:         $if->setActions($actions);
469:         $this->_blocks[] = $if;
470:     }
471: 
472:     /**
473:      * Generates the Sieve script to do the filtering specified in
474:      * the rules.
475:      *
476:      * @return string  The Sieve script.
477:      */
478:     public function generate()
479:     {
480:         global $ingo_storage;
481: 
482:         $filters = $ingo_storage->retrieve(Ingo_Storage::ACTION_FILTERS);
483:         foreach ($filters->getFilterList() as $filter) {
484:             /* Check to make sure this is a valid rule and that the rule
485:                is not disabled. */
486:             if (!$this->_validRule($filter['action']) ||
487:                 !empty($filter['disable'])) {
488:                 continue;
489:             }
490: 
491:             $action = array();
492:             switch ($filter['action']) {
493:             case Ingo_Storage::ACTION_KEEP:
494:                 if (!empty($filter['flags'])) {
495:                     $action[] = new Ingo_Script_Sieve_Action_Addflag(array('flags' => $filter['flags']));
496:                 }
497: 
498:                 $action[] = new Ingo_Script_Sieve_Action_Keep();
499: 
500:                 if (!empty($filter['flags'])) {
501:                     $action[] = new Ingo_Script_Sieve_Action_Removeflag(array('flags' => $filter['flags']));
502:                 }
503:                 break;
504: 
505:             case Ingo_Storage::ACTION_DISCARD:
506:                 $action[] = new Ingo_Script_Sieve_Action_Discard();
507:                 break;
508: 
509:             case Ingo_Storage::ACTION_MOVE:
510:                 if (!empty($filter['flags'])) {
511:                     $action[] = new Ingo_Script_Sieve_Action_Addflag(array('flags' => $filter['flags']));
512:                 }
513: 
514:                 $action[] = new Ingo_Script_Sieve_Action_Fileinto(array_merge($this->_params, array('folder' => $filter['action-value'])));
515: 
516:                 if (!empty($filter['flags'])) {
517:                     $action[] = new Ingo_Script_Sieve_Action_Removeflag(array('flags' => $filter['flags']));
518:                     }
519:                 break;
520: 
521:             case Ingo_Storage::ACTION_REJECT:
522:                 $action[] = new Ingo_Script_Sieve_Action_Reject(array('reason' => $filter['action-value']));
523:                 break;
524: 
525:             case Ingo_Storage::ACTION_REDIRECT:
526:                 $action[] = new Ingo_Script_Sieve_Action_Redirect(array('address' => $filter['action-value']));
527:                 break;
528: 
529:             case Ingo_Storage::ACTION_REDIRECTKEEP:
530:                 if (!empty($filter['flags'])) {
531:                     $action[] = new Ingo_Script_Sieve_Action_Addflag(array('flags' => $filter['flags']));
532:                 }
533: 
534:                 $action[] = new Ingo_Script_Sieve_Action_Redirect(array('address' => $filter['action-value']));
535:                 $action[] = new Ingo_Script_Sieve_Action_Keep();
536: 
537:                 if (!empty($filter['flags'])) {
538:                     $action[] = new Ingo_Script_Sieve_Action_Removeflag(array('flags' => $filter['flags']));
539:                 }
540:                 break;
541: 
542:             case Ingo_Storage::ACTION_MOVEKEEP:
543:                 if (!empty($filter['flags'])) {
544:                     $action[] = new Ingo_Script_Sieve_Action_Addflag(array('flags' => $filter['flags']));
545:                 }
546: 
547:                 $action[] = new Ingo_Script_Sieve_Action_Keep();
548:                 $action[] = new Ingo_Script_Sieve_Action_Fileinto(array_merge($this->_params, array('folder' => $filter['action-value'])));
549: 
550:                 if (!empty($filter['flags'])) {
551:                     $action[] = new Ingo_Script_Sieve_Action_Removeflag(array('flags' => $filter['flags']));
552:                 }
553:                 break;
554: 
555:             case Ingo_Storage::ACTION_FLAGONLY:
556:                 if (!empty($filter['flags'])) {
557:                     $action[] = new Ingo_Script_Sieve_Action_Addflag(array('flags' => $filter['flags']));
558:                 }
559:                 break;
560: 
561:             case Ingo_Storage::ACTION_NOTIFY:
562:                 $action[] = new Ingo_Script_Sieve_Action_Notify(array('address' => $filter['action-value'], 'name' => $filter['name']));
563:                 break;
564: 
565:             case Ingo_Storage::ACTION_WHITELIST:
566:                 $this->_addWhitelistBlocks();
567:                 continue 2;
568: 
569:             case Ingo_Storage::ACTION_BLACKLIST:
570:                 $this->_addBlacklistBlocks();
571:                 continue 2;
572: 
573:             case Ingo_Storage::ACTION_VACATION:
574:                 $this->_addVacationBlocks();
575:                 continue 2;
576: 
577:             case Ingo_Storage::ACTION_FORWARD:
578:                 $this->_addForwardBlocks();
579:                  continue 2;
580: 
581:             case Ingo_Storage::ACTION_SPAM:
582:                 $this->_addSpamBlocks();
583:                 continue 2;
584:             }
585: 
586:             $this->_blocks[] = new Ingo_Script_Sieve_Comment($filter['name']);
587: 
588:             if ($filter['stop']) {
589:                 $action[] = new Ingo_Script_Sieve_Action_Stop();
590:             }
591: 
592:             $test = new Ingo_Script_Sieve_Test();
593:             if ($filter['combine'] == Ingo_Storage::COMBINE_ANY) {
594:                 $test = new Ingo_Script_Sieve_Test_Anyof();
595:             } else {
596:                 $test = new Ingo_Script_Sieve_Test_Allof();
597:             }
598: 
599:             foreach ($filter['conditions'] as $condition) {
600:                 $tmp = '';
601:                 switch ($condition['match']) {
602:                 case 'equal':
603:                     $tmp = new Ingo_Script_Sieve_Test_Relational(array('comparison' => 'eq', 'headers' => $condition['field'], 'value' => $condition['value']));
604:                     $test->addTest($tmp);
605:                     break;
606: 
607:                 case 'not equal':
608:                     $tmp = new Ingo_Script_Sieve_Test_Relational(array('comparison' => 'ne', 'headers' => $condition['field'], 'value' => $condition['value']));
609:                     $test->addTest($tmp);
610:                     break;
611: 
612:                 case 'less than':
613:                     if ($condition['field'] == 'Size') {
614:                         /* Message Size Test. */
615:                         $tmp = new Ingo_Script_Sieve_Test_Size(array('comparison' => ':under', 'size' => $condition['value']));
616:                     } else {
617:                         /* Relational Test. */
618:                         $tmp = new Ingo_Script_Sieve_Test_Relational(array('comparison' => 'lt', 'headers' => $condition['field'], 'value' => $condition['value']));
619:                     }
620:                     $test->addTest($tmp);
621:                     break;
622: 
623:                 case 'less than or equal to':
624:                     $tmp = new Ingo_Script_Sieve_Test_Relational(array('comparison' => 'le', 'headers' => $condition['field'], 'value' => $condition['value']));
625:                     $test->addTest($tmp);
626:                     break;
627: 
628:                 case 'greater than':
629:                     if ($condition['field'] == 'Size') {
630:                         /* Message Size Test. */
631:                         $tmp = new Ingo_Script_Sieve_Test_Size(array('comparison' => ':over', 'size' => $condition['value']));
632:                     } else {
633:                         /* Relational Test. */
634:                         $tmp = new Ingo_Script_Sieve_Test_Relational(array('comparison' => 'gt', 'headers' => $condition['field'], 'value' => $condition['value']));
635:                     }
636:                     $test->addTest($tmp);
637:                     break;
638: 
639:                 case 'greater than or equal to':
640:                     $tmp = new Ingo_Script_Sieve_Test_Relational(array('comparison' => 'ge', 'headers' => $condition['field'], 'value' => $condition['value']));
641:                     $test->addTest($tmp);
642:                     break;
643: 
644:                 case 'exists':
645:                     $tmp = new Ingo_Script_Sieve_Test_Exists(array('headers' => $condition['field']));
646:                     $test->addTest($tmp);
647:                     break;
648: 
649:                 case 'not exist':
650:                     $tmp = new Ingo_Script_Sieve_Test_Exists(array('headers' => $condition['field']));
651:                     $test->addTest(new Ingo_Script_Sieve_Test_Not($tmp));
652:                     break;
653: 
654:                 case 'contains':
655:                 case 'not contain':
656:                 case 'is':
657:                 case 'not is':
658:                 case 'begins with':
659:                 case 'not begins with':
660:                 case 'ends with':
661:                 case 'not ends with':
662:                 case 'regex':
663:                 case 'matches':
664:                 case 'not matches':
665:                     $comparator = (isset($condition['case']) &&
666:                                    $condition['case'])
667:                         ? 'i;octet'
668:                         : 'i;ascii-casemap';
669:                     $vals = array('headers' => preg_replace('/(.)(?<!\\\)\,(.)/',
670:                                                             "$1\n$2",
671:                                                             $condition['field']),
672:                                   'comparator' => $comparator);
673:                     $use_address_test = false;
674: 
675:                     if ($condition['match'] != 'regex') {
676:                         $condition['value'] = preg_replace('/(.)(?<!\\\)\,(.)/',
677:                                                            "$1\n$2",
678:                                                            $condition['value']);
679:                     }
680: 
681:                     /* Do 'smarter' searching for fields where we know we have
682:                      * e-mail addresses. */
683:                     if (preg_match('/^(From|To|Cc|Bcc)/', $condition['field'])) {
684:                         $vals['addresses'] = $condition['value'];
685:                         $use_address_test = true;
686:                     } else {
687:                         $vals['strings'] = $condition['value'];
688:                     }
689: 
690:                     switch ($condition['match']) {
691:                     case 'contains':
692:                         $vals['match-type'] = ':contains';
693:                         if ($use_address_test) {
694:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
695:                         } elseif ($condition['field'] == 'Body') {
696:                             $tmp = new Ingo_Script_Sieve_Test_Body($vals);
697:                         } else {
698:                             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
699:                         }
700:                         $test->addTest($tmp);
701:                         break;
702: 
703:                     case 'not contain':
704:                         $vals['match-type'] = ':contains';
705:                         if ($use_address_test) {
706:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
707:                         } elseif ($condition['field'] == 'Body') {
708:                             $tmp = new Ingo_Script_Sieve_Test_Body($vals);
709:                         } else {
710:                             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
711:                         }
712:                         $test->addTest(new Ingo_Script_Sieve_Test_Not($tmp));
713:                         break;
714: 
715:                     case 'is':
716:                         $vals['match-type'] = ':is';
717:                         if ($use_address_test) {
718:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
719:                         } elseif ($condition['field'] == 'Body') {
720:                             $tmp = new Ingo_Script_Sieve_Test_Body($vals);
721:                         } else {
722:                             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
723:                         }
724:                         $test->addTest($tmp);
725:                         break;
726: 
727:                     case 'not is':
728:                         $vals['match-type'] = ':is';
729:                         if ($use_address_test) {
730:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
731:                         } elseif ($condition['field'] == 'Body') {
732:                             $tmp = new Ingo_Script_Sieve_Test_Body($vals);
733:                         } else {
734:                             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
735:                         }
736:                         $test->addTest(new Ingo_Script_Sieve_Test_Not($tmp));
737:                         break;
738: 
739:                     case 'begins with':
740:                         $vals['match-type'] = ':matches';
741:                         if ($use_address_test) {
742:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['addresses']);
743:                             if (count($add_arr) > 1) {
744:                                 foreach ($add_arr as $k => $v) {
745:                                     $add_arr[$k] = $v . '*';
746:                                 }
747:                                 $vals['addresses'] = implode("\r\n", $add_arr);
748:                             } else {
749:                                 $vals['addresses'] .= '*';
750:                             }
751:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
752:                         } else {
753:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['strings']);
754:                             if (count($add_arr) > 1) {
755:                                 foreach ($add_arr as $k => $v) {
756:                                     $add_arr[$k] = $v . '*';
757:                                 }
758:                                 $vals['strings'] = implode("\r\n", $add_arr);
759:                             } else {
760:                                 $vals['strings'] .= '*';
761:                             }
762:                             if ($condition['field'] == 'Body') {
763:                                 $tmp = new Ingo_Script_Sieve_Test_Body($vals);
764:                             } else {
765:                                 $tmp = new Ingo_Script_Sieve_Test_Header($vals);
766:                             }
767:                         }
768:                         $test->addTest($tmp);
769:                         break;
770: 
771:                     case 'not begins with':
772:                         $vals['match-type'] = ':matches';
773:                         if ($use_address_test) {
774:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['addresses']);
775:                             if (count($add_arr) > 1) {
776:                                 foreach ($add_arr as $k => $v) {
777:                                     $add_arr[$k] = $v . '*';
778:                                 }
779:                                 $vals['addresses'] = implode("\r\n", $add_arr);
780:                             } else {
781:                                 $vals['addresses'] .= '*';
782:                             }
783:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
784:                         } else {
785:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['strings']);
786:                             if (count($add_arr) > 1) {
787:                                 foreach ($add_arr as $k => $v) {
788:                                     $add_arr[$k] = $v . '*';
789:                                 }
790:                                 $vals['strings'] = implode("\r\n", $add_arr);
791:                             } else {
792:                                 $vals['strings'] .= '*';
793:                             }
794:                             if ($condition['field'] == 'Body') {
795:                                 $tmp = new Ingo_Script_Sieve_Test_Body($vals);
796:                             } else {
797:                                 $tmp = new Ingo_Script_Sieve_Test_Header($vals);
798:                             }
799:                         }
800:                         $test->addTest(new Ingo_Script_Sieve_Test_Not($tmp));
801:                         break;
802: 
803:                     case 'ends with':
804:                         $vals['match-type'] = ':matches';
805:                         if ($use_address_test) {
806:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['addresses']);
807:                             if (count($add_arr) > 1) {
808:                                 foreach ($add_arr as $k => $v) {
809:                                     $add_arr[$k] = '*' . $v;
810:                                 }
811:                                 $vals['addresses'] = implode("\r\n", $add_arr);
812:                             } else {
813:                                 $vals['addresses'] = '*' .  $vals['addresses'];
814:                             }
815:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
816:                         } else {
817:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['strings']);
818:                             if (count($add_arr) > 1) {
819:                                 foreach ($add_arr as $k => $v) {
820:                                     $add_arr[$k] = '*' . $v;
821:                                 }
822:                                 $vals['strings'] = implode("\r\n", $add_arr);
823:                             } else {
824:                                 $vals['strings'] = '*' .  $vals['strings'];
825:                             }
826:                             if ($condition['field'] == 'Body') {
827:                                 $tmp = new Ingo_Script_Sieve_Test_Body($vals);
828:                             } else {
829:                                 $tmp = new Ingo_Script_Sieve_Test_Header($vals);
830:                             }
831:                         }
832:                         $test->addTest($tmp);
833:                         break;
834: 
835:                     case 'not ends with':
836:                         $vals['match-type'] = ':matches';
837:                         if ($use_address_test) {
838:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['addresses']);
839:                             if (count($add_arr) > 1) {
840:                                 foreach ($add_arr as $k => $v) {
841:                                     $add_arr[$k] = '*' . $v;
842:                                 }
843:                                 $vals['addresses'] = implode("\r\n", $add_arr);
844:                             } else {
845:                                 $vals['addresses'] = '*' .  $vals['addresses'];
846:                             }
847:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
848:                         } else {
849:                             $add_arr = preg_split('(\r\n|\n|\r)', $vals['strings']);
850:                             if (count($add_arr) > 1) {
851:                                 foreach ($add_arr as $k => $v) {
852:                                     $add_arr[$k] = '*' . $v;
853:                                 }
854:                                 $vals['strings'] = implode("\r\n", $add_arr);
855:                             } else {
856:                                 $vals['strings'] = '*' .  $vals['strings'];
857:                             }
858:                             if ($condition['field'] == 'Body') {
859:                                 $tmp = new Ingo_Script_Sieve_Test_Body($vals);
860:                             } else {
861:                                 $tmp = new Ingo_Script_Sieve_Test_Header($vals);
862:                             }
863:                         }
864:                         $test->addTest(new Ingo_Script_Sieve_Test_Not($tmp));
865:                         break;
866: 
867:                     case 'regex':
868:                         $vals['match-type'] = ':regex';
869:                         if ($use_address_test) {
870:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
871:                         } elseif ($condition['field'] == 'Body') {
872:                             $tmp = new Ingo_Script_Sieve_Test_Body($vals);
873:                         } else {
874:                             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
875:                         }
876:                         $test->addTest($tmp);
877:                         break;
878: 
879:                     case 'matches':
880:                         $vals['match-type'] = ':matches';
881:                         if ($use_address_test) {
882:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
883:                         } elseif ($condition['field'] == 'Body') {
884:                             $tmp = new Ingo_Script_Sieve_Test_Body($vals);
885:                         } else {
886:                             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
887:                         }
888:                         $test->addTest($tmp);
889:                         break;
890: 
891:                     case 'not matches':
892:                         $vals['match-type'] = ':matches';
893:                         if ($use_address_test) {
894:                             $tmp = new Ingo_Script_Sieve_Test_Address($vals);
895:                         } elseif ($condition['field'] == 'Body') {
896:                             $tmp = new Ingo_Script_Sieve_Test_Body($vals);
897:                         } else {
898:                             $tmp = new Ingo_Script_Sieve_Test_Header($vals);
899:                         }
900:                         $test->addTest(new Ingo_Script_Sieve_Test_Not($tmp));
901:                         break;
902:                     }
903:                 }
904:             }
905: 
906:             $if = new Ingo_Script_Sieve_If($test);
907:             $if->setActions($action);
908:             $this->_blocks[] = $if;
909:         }
910: 
911:         /* Add blocks that have to go to the end. */
912:         foreach ($this->_endBlocks as $block) {
913:             $this->_blocks[] = $block;
914:         }
915: 
916:         return $this->toCode();
917:     }
918: 
919: }
920: 
API documentation generated by ApiGen