[Evolution-hackers] Filtering and mail split



As some of you may know, I've been looking into moving mail down to the
e-d-s level.  As a first step, I'm figuring out where to draw the line
between the front end and backend.  At the moment, I'm focusing on
filtering.  I think that the filtering functionality clearly belongs in
the backend (we want to filter emails as they come in regardless of
whether the UI is running or not).  The thing I'm trying to figure out
right now is what that means for the filter-related classes within
evolution (i.e. the stuff in the filter/ directory).  My first instinct
was that these classes belonged in the backend since that is the part
that should be doing the filtering.  However, as I looked at it more, I
wasn't so sure, and I'd really appreciate insight from people who might
have a longer history with this code than I do.  (FYI, while I was
getting more familiar with the filter code, I wrote up some
documentation that you might find helpful:
http://live.gnome.org/Evolution/Filters)

First, let me lay out a few requirements as I see them.

For the backend:
A) The backend must load the saved filters from disk at startup on its
own.  It can't depend on the frontend to load them and send them down to
the backend because we can't assume that the frontend will be running.
B) The backend needs access to the s-expression representation of the
saved filters (and a unique name for the saved filter), but doesn't
really need any other information to function properly.

For the frontend (note that when I say 'frontend', it may be the MUA
itself, or it may be a helper client library like some future
libedsmailui library):
A) The frontend needs to know the list of saved filters (so it can
present them to the user for editing).
B) The frontend needs to know the possible FilterParts that can be used
to construct a new saved filter.
C) The frontend needs to know the valid values for each of the filter
elements.

There are probably other requirements as well, but that's hopefully
enough for the current discussion.

Potential approaches:
====================
1) The most obvious (to me) approach to this issue was to move the
filter classes into the backend and provide a DBus API for the frontend
to get the list of active filters, etc.  The one big issue with this
approach is the virtual get_widget() vfunc for all filter-related
classes.  Obviously, passing a GtkWidget* over DBus is not going to
work, so if we were going to put these filter classes in the backend,
we'd have split the class, remove this vfunc and move the
widget-constructing functionality into the front end.  This is
problematic for several reasons.  First of all, to implement a new type
of filter element, you'd need to implement the base part in e-d-s and
then implement the UI part in the frontend.  Besides the minor annoyance
of having to implement things in two different places, it introduces
more opportunities for version mismatches between the frontend and
backend to create problems (i.e. the version of the backend that is
running knows about more types of filters than the UI does... then what
happens when the user tries to edit a filter that uses one of those new
filter elements?).  But my big issue with this approach is simply that I
can't think of an elegant API that would allow the frontend to construct
the widgets for the filter elements.  A DBus API to get the list of
FilterElements for a FilterPart would simply return a list of
EFilterElement (i.e. the base class).  But the API of the base class is
not sufficient to construct the editing widget.  To construct a widget
for a 'option' filter element, you need the extra information and API
provided by the EFilterOption class.

2) Move the filter/ files to a base library that both the frontend and
backend link to.  They both use these classes to load and parse the
saved filter xml files directly.  When a filter is added/removed/changed
by the frontend, it sends a notification to the backend to update its
filters somehow.  This approach has obvious drawback that probably don't
need explaining, but just in case:  the backend would have completely
unnecessary dependency on GTK+, there is duplication of responsibility,
it feels incredibly ugly, the frontend and backend need to be careful to
coordinate that they're both loading the saved files from the same
location, etc, etc.

3) Keep the filter classes in the frontend.  The backend doesn't really
need to know anything about potential values for elements or which
FilterParts are combined together to generate the resulting
S-expression.  All it really cares about is the final S-expression.
Unfortunately, to generate this S-expression from the saved filter XML
files, you need to parse everything and then map the values found in the
<ruleset> nodes to the elements in <partset> (the filter parts contain
the rules for generating the s-exp code from the filter values, but the
rule provide the values).  We can avoid having to parse the entire XML
tree if we save the full s-expression for each filter to disk along with
the xml description of all of the elements that it is built from.  Then
the backend could simply load the name and s-expression for each filter
at startup.  The frontend would be responsible for parsing the full xml
describing the filter types, and setting up the filter contexts like it
currently does.  When a user changed / added / removed a filter, the
frontend would simply send the new s-expression associated with the
named filter down to the backend (or notify the backend that it should
be removed) and cache the new s-expression to disk for the backend to
load on next startup.  The drawbacks of this option are: a) it feels
rather hacky, b) the frontend and backend still need to coordinate on
where to load the files from.

Try as I might, I can't think of a better solution than #3.  I'm hoping
somebody else out there might be able to help me through this design
block (or convince me that one of the above options is acceptable)

-- 
Jonathon Jongsma <jonathon jongsma collabora co uk>




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]