# Sieve syntax highlighting test
# see RFC 5228

# comments §2.3.

# Single line with alerts TODO ###
<beginfold id='1'>/*</beginfold id='1'>
 Multiline comment with alerts FIXME
 this also should be folding region
 <endfold id='1'>*/</endfold id='1'>

# literal data §2.4.
# numbers §2.4.1.
42
100K
10M
3G

# strings §2.4.2.
"string"
"string\nwith\"special chars"
# not a string
"multi \
 line \
 #with\a \
 continuation"
# not a string
<beginfold id='2'>text:</beginfold id='2'>
Multiline
string\" "with quotes"
or # comments
this should also be a folding region
.dot
..dot
dotstuffed dot:
..
ending with a single .
<endfold id='2'>.</endfold id='2'>

# encoded characters §2.4.2.4.
# valid
"$${hex:24 24}"
"${unicode:40}"
"$${hex:40}"
"${hex: da }"
"${hex:FE }"
"${HEX: 40}"
"${unicode:40}"
"${UNICODE:40}"
"${UnICoDE:0000040}"
"${Unicode:ff}"
#invalid
"${hex:40"
"${hex:4${hex:30}}"
"${ unicode:40}"
"${Unicode:Cool}"
# semantic errors, syntactically correct
"${hex:400}"
"${unicode:200000}"
"${Unicode:DF01}"

# test lists §2.5.1
if anyof (not exists ["From", "Date"],
          header :contains "from" "fool@example.com") <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'>
if allof (not exists ["From", "Date"],
          header :contains "from" "fool@example.com") <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'>

# match types §2.7.1.
:contains
:matches
:is

# comparators §2.7.3.
if header :contains :comparator "i;octet" "Subject" "MAKE MONEY FAST" <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'>

# comparison against addresses §2.7.4.
:localpart
:domain
:all

# commands §2.9.
keep;
fileinto "inbox.bla";
redirect "test@kde.org";
discard;

# control if §3.1.
# this also should create folding regions
if header :contains "from" "foo" <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'> elsif header :contains ["subject"] ["$$$"] <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'> else <beginfold id='3'>{</beginfold id='3'>
    fileinto "INBOX";
<endfold id='3'>}</endfold id='3'>

# control require §3.2.
require "fileinto";
require ["vacation", "imapflags"];

# control stop §3.3.
stop;

# test commands §5.
address
allof
anyof
exists
false
header
not
size
true

# test address §5.1.
if address :is :all "from" "kde@example.com" <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'> elsif address :domain :is ["From", "To"] "example.com" <beginfold id='3'>{</beginfold id='3'> # comment
    keep; # comment
<endfold id='3'>}</endfold id='3'>

# test envelope §5.4.
if envelope :all :is "from" "kde@example.com" <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'>

# test exists §5.5.
if not exists ["From","Date"] <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'>

# test header §5.7.
not header :matches "Cc" "?*"

# test size §5.9.
if size :over 500K <beginfold id='3'>{</beginfold id='3'> discard; <endfold id='3'>}</endfold id='3'>
if size :under 1M <beginfold id='3'>{</beginfold id='3'> keep; <endfold id='3'>}</endfold id='3'> else <beginfold id='3'>{</beginfold id='3'> discard; <endfold id='3'>}</endfold id='3'>


<beginfold id='1'>/*</beginfold id='1'>
 * Extensions
 * see https://www.iana.org/assignments/sieve-extensions/sieve-extensions.xhtml
 <endfold id='1'>*/</endfold id='1'>

# Body RFC5173
:raw
:content
:text
if body :raw :contains "MAKE MONEY FAST" <beginfold id='3'>{</beginfold id='3'>
    discard;
<endfold id='3'>}</endfold id='3'>
if body :content "text" :contains ["bla", "blub"] <beginfold id='3'>{</beginfold id='3'>
    fileinto "inbox.foo";
<endfold id='3'>}</endfold id='3'>

# Convert RFC6558
require ["convert"];
convert "image/tiff" "image/jpeg" ["pix-x=320","pix-y=240"];

# Copy RFC3894
require ["copy", "fileinto"];
fileinto :copy "incoming";

# Date RFC5260
require ["date", "relational", "fileinto"];
if allof(header :is "from" "boss@example.com",
         date :value "ge" :originalzone "date" "hour" "09",
         date :value "lt" :originalzone "date" "hour" "17")
    <beginfold id='3'>{</beginfold id='3'> fileinto "urgent"; <endfold id='3'>}</endfold id='3'>
if anyof(date :is "received" "weekday" "0",
         date :is "received" "weekday" "6")
<beginfold id='3'>{</beginfold id='3'> fileinto "weekend"; <endfold id='3'>}</endfold id='3'>
if anyof(currentdate :is "weekday" "0",
         currentdate :is "weekday" "6",
         currentdate :value "lt" "hour" "09",
         currentdate :value "ge" "hour" "17")
<beginfold id='3'>{</beginfold id='3'> redirect "pager@example.com"; <endfold id='3'>}</endfold id='3'>
if allof(currentdate :value "ge" "date" "2007-06-30",
         currentdate :value "le" "date" "2007-07-07")
<beginfold id='3'>{</beginfold id='3'> vacation :days 7  "I'm away during the first week in July."; <endfold id='3'>}</endfold id='3'>

require ["date", "variables", "fileinto"];
if currentdate :matches "month" "*" <beginfold id='3'>{</beginfold id='3'> set "month" "${1}"; <endfold id='3'>}</endfold id='3'>
if currentdate :matches "year"  "*" <beginfold id='3'>{</beginfold id='3'> set "year"  "${1}"; <endfold id='3'>}</endfold id='3'>
fileinto "${month}-${year}";

require ["variables", "date", "editheader"];
if currentdate :matches "std11" "*" <beginfold id='3'>{</beginfold id='3'>addheader "Processing-date" "${0}";<endfold id='3'>}</endfold id='3'>

require ["date", "relational", "index"];
if date :value "gt" :index 2 :zone "-0500" "received" "iso8601" "2007-02-26T09:00:00-05:00"
<beginfold id='3'>{</beginfold id='3'> redirect "aftercutoff@example.org"; <endfold id='3'>}</endfold id='3'>

if header :index 1 :matches "received" "*(* [*.*.*.*])*" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Duplicate RFC7352
require ["duplicate", "variables"];
if duplicate <beginfold id='3'>{</beginfold id='3'> discard; <endfold id='3'>}</endfold id='3'>
if duplicate :header "message-id" <beginfold id='3'>{</beginfold id='3'> discard; <endfold id='3'>}</endfold id='3'>
if header :matches "message-id" "*" <beginfold id='3'>{</beginfold id='3'>
    if duplicate :uniqueid "${0}" <beginfold id='3'>{</beginfold id='3'> discard; <endfold id='3'>}</endfold id='3'>
<endfold id='3'>}</endfold id='3'>

# Editheader RFC5293
addheader "X-Hello" "World";
deleteheader :index 1 "X-Hello";

# Enclose RFC5703
:mime
:anychild
:type
:subtype
:contenttype
:param
replace
enclose
extracttext
if header :mime :type "Content-Type" "image" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
replace "Executable attachment removed by user filter";
foreverypart <beginfold id='3'>{</beginfold id='3'>
    if header :mime :param "filename" :matches ["Content-Type", "Content-Disposition"]
        ["*.com", "*.exe", "*.vbs", "*.scr", "*.pif", "*.hta", "*.bat", "*.zip" ] <beginfold id='3'>{</beginfold id='3'>
        # these attachment types are executable
        enclose :subject "Warning" <beginfold id='2'>text:</beginfold id='2'>
WARNING! The enclosed message contains executable attachments.
These attachment types may contain a computer virus program
that can infect your computer and potentially damage your data.
<endfold id='2'>.</endfold id='2'>
;
        break;
    <endfold id='3'>}</endfold id='3'>
<endfold id='3'>}</endfold id='3'>
extracttext :first 100 "msgcontent";

# Notify RFC5435
notify :importance "1" :message "This is probably very important" "mailto:kde@example.com";
notify :message "${from_addr}${env_from}: ${subject}" "mailto:kde@example.com";
if not valid_notify_method ["mailto:", "http://gw.example.net/notify?test"] <beginfold id='3'>{</beginfold id='3'> stop; <endfold id='3'>}</endfold id='3'>
if notify_method_capability "xmpp:tim@example.com?message;subject=SIEVE" "Online" "yes" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
set :encodeurl "body_param" "stuff";

# Envelope DSN RFC6009
if envelope "notify" "SUCCESS" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if allof (envelope "notify" "FAILURE", envelope :comparator "i;ascii-numeric" :count "eq" "notify" "1") <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if envelope :matches "orcpt" "rfc822;*@example.com" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if anyof (envelope :contains "bytimerelative" "-", envelope :value "eq" :comparator "i;ascii-numeric" "bytimerelative" "0") <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
redirect :copy :notify "NEVER" "elsewhere@example.com";
redirect :copy :bytimerelative 600 "cellphone@example.com";
redirect :copy :bytimeabsolute "${date}T20:00:00${zone}" :bymode "return" "cellphone@example.com";

# Environment RFC5183
if environment :contains "item" "" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Reject RFC5429
ereject "I no longer accept mail from this address";
reject <beginfold id='2'>text:</beginfold id='2'>
Your message is too big.  If you want to send me a big attachment,
put it on a public web site and send me a URL.
<endfold id='2'>.</endfold id='2'>
;

# External Lists RFC6134
if envelope :list "from" ":addrbook:default" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if currentdate :list "date" "tag:example.com,2011-01-01:localHolidays" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if allof (envelope :detail "to" "mylist", header :list "from" "tag:example.com,2010-05-28:mylist") <beginfold id='3'>{</beginfold id='3'>
    redirect :list "tag:example.com,2010-05-28:mylist";
<endfold id='3'>}</endfold id='3'>
if string :list "${ip}" "tag:example.com,2011-04-10:DisallowedIPs" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if header :mime :param "filename" :list ["Content-Type", "Content-Disposition"] "tag:example.com,2011-04-10:BadFileNameExts" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# ihave RFC5463
if ihave "fileinto" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
error "failed!";

# IMAP Sieve RFC6785
if anyof (environment :is "imap.cause" "APPEND", environment :is "imap.cause" "COPY")  <beginfold id='3'>{</beginfold id='3'>
    if environment :is "imap.mailbox" "ActionItems" <beginfold id='3'>{</beginfold id='3'>
        redirect :copy "actionitems@example.com";
    <endfold id='3'>}</endfold id='3'>
<endfold id='3'>}</endfold id='3'>

# IMAP4 Flags RFC5232
setflag "\\Deleted";
setflag "flagvar" "\\Flagged";
addflag "flagvar" "\\Deleted";
addflag "flagvar" ["\\Deleted", "\\Answered"];
removeflag "flagvar" "$MDNRequired";
hasflag :contains "MyVar" "Junk"
hasflag :contains "${MyVar}" ["label", "forward"]
hasflag :count "ge" :comparator "i;ascii-numeric" "MyFlags" 2
fileinto :flags "\\Deleted" "INBOX.bla";

# Include RFC6609
include :personal "always_allow";
include :global "spam_tests";
return;
global "i_am_on_vacation";
set "global.i_am_on_vacation" "1";

# Mailbox RFC5490
if mailboxexists "bla" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
fileinto :create "inbox.bla";
if metadata :is "INBOX" "/private/vendor/vendor.isode/auto-replies" "on" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if metadataexists "INBOX" "/private/vendor/foo" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if servermetadata :matches "/private/vendor/vendor.isode/notification-uri" "*" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if servermetadataexists "/private/vendor/foo" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Regexp (draft)
if not address :regex ["to", "cc", "bcc"] "me(\\+.*)?@company\\.com" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Relational RFC5231
if address :count "ge" :comparator "i;ascii-numeric" ["to", "cc"] ["3"] <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if header :value "lt" :comparator "i;ascii-numeric" ["x-priority"] ["3"] <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Spamtest RFC5235
if spamtest :value "eq" :comparator "i;ascii-numeric" "0" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
elsif spamtest :value "ge" :comparator "i;ascii-numeric" "3" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
elsif spamtest :percent :value "lt" :comparator "i;ascii-numeric" "37" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if virustest :value "eq" :comparator "i;ascii-numeric" "4" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Subaddress RFC5233
if envelope :user "to" "postmaster" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>
if envelope :detail "to" "mta-filters" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Vacation RFC5230
vacation "I'm out";
vacation :subject "Automatic response to: ${1}"
                  "I'm away -- send mail to foo in my absence";
vacation :handle "ran-away" "I'm out";
vacation :mime <beginfold id='2'>text:</beginfold id='2'>
   Content-Type: multipart/alternative; boundary=foo

   --foo

   Hello ${sender}, I'm at the beach relaxing.

   --foo
   Content-Type: text/html; charset=us-ascii

   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
    "http://www.w3.org/TR/REC-html40/strict.dtd">
   <HTML><HEAD><TITLE>How to relax</TITLE>
   <BASE HREF="http://home.example.com/pictures/"></HEAD>
   <BODY><P>I'm at the <A HREF="beach.gif">beach</A> relaxing.
   </BODY></HTML>

   --foo--
<endfold id='2'>.</endfold id='2'>
;
vacation :days 23 :addresses ["kde@example.edu"] "I'm away until October 19.";

# Vacation Seconds RFC6131
vacation :addresses ["kde@example.edu"] :seconds 1800
    "I am in a meeting, and do not have access to email.";

# Variables RFC5229
"&%${}!" # invalid
"${doh!}" #invalid
"${company}"
"bla ${var42} blub"
"${1}"
"${BAD${Company}" # second one is the variable
"${President, ${Company} Inc.}" # inner one is the variable
set "var" "value";
set "var2" "${var}";

set "a" "juMBlEd lETteRS";
set :length "b" "${a}";
set :lower "b" "${a}";
set :upperfirst "b" "${a}";
set :upperfirst :lower "b" "${a}";
set :quotewildcard "b" "Rock*";
set :lowerfirst "b" "${a}";

if string :matches " ${state} " "* pending *" <beginfold id='3'>{</beginfold id='3'><endfold id='3'>}</endfold id='3'>

# Dovecot debug extension
require "vnd.dovecot.debug";
if header :contains "subject" "hello" <beginfold id='3'>{</beginfold id='3'>
    debug_log "Subject header contains hello!";
<endfold id='3'>}</endfold id='3'>
