[Haskell-cafe] Status of MIME Strike Force

Jeremy Shaw jeremy.shaw at linspireinc.com
Wed Jun 27 14:22:10 EDT 2007


At Wed, 27 Jun 2007 18:54:58 +0200 (CEST),
Arie Peterson wrote:

> What is the status of the MIME Strike Force?
> 
> The goals proposed at
> <http://www.haskell.org/haskellwiki/Libraries_and_tools/MIMEStrikeForce>
> promise a very useful library. Has the design been initiated?

Currently it is on hold while I work on some other higher priority
projects. But, I do hope to get back to it soon. (Or, perhaps someone
else will have time to work on it).

It seems to me that the mime-string package is very close to what we
need for parsing MIME messages. If all you care about is parsing MIME
messages, I highly recommend it.

This leaves the problem of creating and transforming MIME
messages. The real difficulty in this area is creating a good API. If
you want to take a peek at what I have, take a look at:

http://www.n-heptane.com/nhlab/repos/haskell-mime/APIs.hs

Currently I am difficulty dealing with headers that could appear more
than once.

For example, the 'Keywords' header can appear multiple times. So,
there are two cases to handle:

 1. add an additional Keywords header
 2. deleted any existing Keywords headers and add the new one

Other fields, such as 'Subject', can appear only once.

One way to express a filter that modifies an existing message is the
following:

> exampleHeaders =
>    ( (setHeader (Subject "whee")) .
>      (setHeader (Subject "bork")).
>      (addHeader (Keywords ["baz", "bar", "bam"])) .
>      (addHeader (Keywords ["zip", "zap", "zop"]))
>    )

where setHeader ensures that a header only appears once, and addHeader
appends the header, leaving existing instances alone. The type system
ensures that you can never call addHeader on (Subject
"whee"). Unfortunately, that code seems a bit verbose.

we can make some helper functions that reduce the verbosity a bit,

> subject = setHeader . Subject
> keywords = addHeader . Keywords

> exampleHeaders3 :: [RawHeader] -> [RawHeader]
> exampleHeaders3 =
>    ((subject "whee") .
>     (subject "bork") .
>     (keywords ["baz", "bar", "bam"]) .
>     (keywords ["zip", "zap", "zop"]))

That is nice, except that we don't know which headers are going to use
setHeader and which are doing to use addHeader. So, the results might
be a bit suprising. Additionally, keywords always uses addHeader, but
in some cases we might want it to use setHeader.

Another option is to trying to use infix operators, such as:

(.+.) for setHeader 
(.*.) for addHeader

> exampleHeaders2 :: [RawHeader]
> exampleHeaders2 =
>    ((Subject "whee") .+. 
>     (Subject "bork") .+.
>     (Keywords ["baz", "bar", "bam"]) .*.
>     (Keywords ["zip", "zap", "zop"]) .*.
>     empty
>    )

This is good because:

 1. is it shorter than the first example that used setHeader/addHeader

 2. the information about whether setHeader/addHeader is being used is
    preserved.

 3. it is easy to choose which one you want (setHeader/addHeader)

But, it is also really wonky because the operator has a bit of a
postfix feel to it. For example, it is the .*. at the end of this line
that is making it use addHeader. 

>     (Keywords ["baz", "bar", "bam"]) .*.

If we wanted to use setHeader here, we would have to change it to:

>     (Keywords ["baz", "bar", "bam"]) .+.

This behaviour seems pretty unintutive.

A whole other area I have not dealt with yet is data-mining and
filters that depend on the values of existing fields. For example:

 1. find all the headers that contain the string XXX
 2. find all the Keywords fields and merge them into a single Keywords field

So, that is where I currently am. Once the API is worked out, I think
things should progress pretty easily. If you have any ideas, let me
know. I think I may be picking this up again in September or October.

HaXml, SYB, Uniplate, and HList seem like good places to get some ideas. If
anyone has suggestions for other projects to look at, let me know.

j.



More information about the Haskell-Cafe mailing list