ietf-mta-filters
[Top] [All Lists]

Re: variables: open issue a) date variables

2003-05-07 13:59:18

[Marc Mutz]:

  It's a side-effect of executing setdate. I call this a
  side-effect, since it's not an explicit "set".

alright.

(easily fixed, just specify lexical sorting of the "set" at all
times.)

  I always wondered why imapflags didn't include a flag test. It
  should, esp. if one considers the include extension where a
  included script doesn't know what it's parent has already done and
  might want to know.

agreed.  the current method is to use a :matches, which will work, but
is a bit roundabout.

wouldn't it be better to make generic functions for this?
    addflag "flag" "\\Flagged";
changes ${flag}.  you'd now use
    keep :flags "${flag}";
rather than
    keep :globalflags;
and
    keep :flags "${flag} \\Flagged";
instead of
    keep :globalflags_plus "\\Flagged";

some scripts may become more verbose, but the complexity of the
IMAPFLAGS is decreased, IMO.  (ADDFLAG and REMOVEFLAG could move to a
separate extension.)

  One could always add the feature to accept multiple flags per string 
  argument, so you can use

  set "myflags" "${#imapflags}" # save away
  # ...
  setflags "${myflags}" # restore

  I fact, you already used that feature in the code above.

yep.

  Also, keep in mind that imapflags implementations already exist
  and you can imagine what a confusion would arise if addflags' et
  al. syntax would be changed.

I don't think this is something we should worry too much about.
deploying features before they are standardised is a gamble.

  mark
  - equivalent to addflag "\\Flagged"

  unmark
  - equivalent to removeflag "\\Flagged"

what is the rationale for MARK and UNMARK?  according to the draft
these actions are _not_ equivalent to ADDFLAG "\\Flagged".

  But IIRC, it's suggested they are. However, this is nitpicking
  again, since it's clear that the exact (un)mark semantics are
  implementation-defined. I've just chosen the obvious one.

I was just wondering why their effect is allowed to be implementation
defined.  I can see that MARK/UNMARK are useful shorthands.

  Ok, here's what I think are properties of system variables, why
  they are needed and why they should be prefixed:

I agree they need to be recognisable by syntax alone.  one type of
prefix could be "date." or "imap.", ie. the distinguishing feature is
the presence of one or more periods.

  3. They may represent concepts that are not naturally represented
     as strings.

     Examples: ${#imapflags} is a set of imap flags, not a string.
               ${#currentdate} is a number or struct tm or whatever, not a
               string.

     There are many issues if you allow ${#imapflags} to be "set" by
     the user (duplicate or invalid flags, ordering
     issues). However, it's a variable (remember that imapflags was
     what prompted a variables extension in the first place, even if
     you were not personally driven by that) and there was objection
     to define extensions that have any kind of "internal variable"
     (as imapflags once called it) without first having variables
     for Sieve in general.

I don't understand this reasoning.  you want "internal variables" with
properties very different from those of the general variables.  where
is the connection between the features?

     It is, however, potentially very useful to allow interpolation
     into strings, and a system variable declaration must specify
     the string representation to use. I've already given an example
     for ${#imapflags}, ${#currentdate} could be interpolated in
     rfc2822 format.

     So system variables could be handled internally in their
     natural representation, with a string representation being
     required only on expansion into strings, which should be pretty
     rare.

ok.  I honestly don't know what's the best way to handle the IMAP
flags.

1)
part of me wants to add a list variable type.  the main sticky point
is the interpolation.  my suggestion was:

  set "foo" [ "one", "two", "three" ];
  set "bar" [ "${foo}", "four" ];
  set "zot" [ "woo${foo}hoo" ];

now ${bar} is [ "one", "two", "three", "four" ] and ${zot} is [ "woo",
"one", "two", "three", "four", "hoo" ].  this makes "${foo}${bar}"
equivalent with [ "${foo}", "${bar}" ].

to go with this, we'd need a prune command to remove an element from a
list.  actually we need two, one by position, and one by value.  for
imapflags, an append command would be useful as well (it's not worth
worrying about duplicates.)

one problem with this is run-time syntax errors, like

  set "folder" [ "foo", "bar" ];
  fileinto "${folder}";

this could be solved by making making a new list variable syntax,
e.g., @{folder} becomes a list, while ${folder} is becomes a single
string with a single space as delimiter or something.


2)
part of me thinks strings will work OK.  it just needs careful
programming to keep everything padded with spaces.

  set "flags" "${flags} \\Flagged ";  # note trailing space
  if string :matches "${flags}" "* \\Flagged *" {
    set "flags" "${1} ${2}";
  }

3)
part of me thinks an intrinsic variable is the solution which appears
cleanest to the user.

why do you need variables at all for IMAP flags?  to keep state, it
seems.

  if something {
     addflag "\\Flagged";
     if somethingelse {
        addflag "Big";
        keep :globalflags;
     }
  }
  # now we want to restore the flags to the values before the if.
  # or do we?

sorry, I can't come up with a credible example.

  4. Their values may not be computed with Sieve.

     You said setdate would be a macro for a list of set's. But it
     isn't.  You can't represent setdate "+0200" like that.

I meant as seen from an optimising Sieve parser, not from a user
perspective.  it wasn't a good comparison, anyway.

     E.g. a hypothetical ${#envelope_sender} system variable would
     not be a good idea, since you can always obtain that by using
     the matches-set idiom:
       if :envelope :all :matches "from" "*" {
         set "myenvelopesender" "${1}";
       }

it seems to me Sieve scripts will soon consist of mostly matches-set
idioms ... ;-)

  5. Their values may not be available from the message.

     Example: ${#currentdate}

  I now agree that ${year} as specified is not a proper system
  variable.

  Here's a proposal for a date test (which is important to have in
  it own right) that makes setdate superfluous by using the
  matches-set idiom to explicitly set the setdate variables:

  if date :current :timezone "+0200" :hour :matches "*" {
    set "${hour}" "${1}";
  }

you won't get daylight savings time handled correctly this way.
compare with

  setdate "Europe/Oslo";
  if not string "${timezone}" "Europe/Oslo" {
    setdate "+0100";
  }

ie., use Europe/Oslo if the server recognises the time zone, otherwise
fall back to +0100.

  where the date test syntax would be:

  date [COMPARATOR] WHICH [TIMEZONE] [DATE-PART] [MATCH-TYPE]
       <key-list: string-list>

  WHICH := ":current" / ":received" / ":sent"
           / ( ":header" <headerfield: string-list> )
  DATE-PART := ":weekday" / ":day" / ":month" / ":year"
           / ":hour" / ":minute" / ":second" / ":numericzone"
           / ":all" / ... ; ":all" is default
  TIMEZONE := ":timezone" <timezone: string>
       ; server's local timezone is default for :current,
         timezone specified in the header is default for :received, :sent
         and :header.

I think this is nice.  but for a user simply wanting to save his mail
in different folders depending on month would write

  setdate;
  fileinto "INBOX.${year}-${month}";

which now becomes

  if date :current :year :matches "*" {
     set "year" "${1}";
  }
  if date :current :month :matches "*" {
     fileinfo "INBOX.${year}-${1}";
  }

  Together with the relational extension and a rfc822-date
  comparator,

please make it an ISO 8601 date comparator ...

  And for those that want "old" setdate:

    set "setdate_timezone" "CEST"
    include :global "setdate";

  where "setdate" includes the matches-set idioms:

:-)

the existence of a global "setdate" script is not guaranteed.  isn't
it better to make the support for this certain?  I think your date
test and SETDATE can co-exist.

  In this scenario, ${#currentdate} would be a system variable with
  all properties as defined above: It affects the date :current
  test, is read-only, it's natural representation is not a string,
  it's value can't be computed with Sieve and it can't be extracted
  from the message.

but is this a good thing, or do we want to make generic mechanisms
instead?

-- 
Kjetil T.                       |  read and make up your own mind
                                |  http://www.cactus48.com/truth.html