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 <[email protected]> _______________________________________________ Evolution-hackers mailing list [email protected] http://mail.gnome.org/mailman/listinfo/evolution-hackers
