Followup to bug 241197 -- or -- feedback from an extension developer

Jonathan Protzenko jonathan.protzenko at
Wed Mar 17 21:42:21 UTC 2010


As proposed by asuth in the latest comments on bug 241197, I'd like to
offer some feedback from my experience developing an extension for
Thunderbird 3. I've had to deal with ugly parts of the code, and I think
I might have some (constructive, I hope) remarks to offer. As this
newly-created list seems to be the right place to do so, I'm offering my
thoughts. Maybe we will be able to set some specific goals that will
provide better APIs for extension developers, and foster the development
of more cool extensions :).

To sum things up, I'm developing an extension called GMail Conversation
View [1] that, as the name indicates, changes the regular thread summary
code into a "Gmail-like" conversation view, including your own messages
and stuff (see [2]). I decided to tackle this issue because I've been
wanting such a thing for years, and I'm convinced Thunderbird 3 has some
innovating features that make it worth spending some time on it. I'm
really hoping for more innovations in future versions of Thunderbird and
I like to think that having nice extensions such as mine prevents people
from switching to Postbox (as some people said in the comments an AMO)
or GMail or whatever.

First of all, it was a real relief dealing with the revamped codebase
from Thunderbird 3. Many parts of the code have been ported to JS (I'm
thinking about things like folderPane.js and messageDisplay.js here,
among others). These are much cleaner and much easier to work with than
previous code, that's really great. Moreover, without the Gloda API, I
would not be able to design such an extension, so congratulations for
all the hard work.

I would also like to thank all the people in #maildev who've always been
patient at answering my dumb questions and who have always been
incredibly helpful. Thanks guys :).

However, there are still some key points that make it excruciatingly
painful to design extensions. I will start with some general thoughts,
then move on to more specific points (such as: "Gloda doesn't provide
feature X or Y").

*I. General remarks*

One of the most useful things I discovered was
-- however, it's only after struggling for a few months that I
discovered it thanks to standard8 who incidentally mentioned it on IRC.
How I wish I knew that sooner! :). What's missing is the same kind of
diagram but in a more general way. How the folderPane, the
messageDisplay, the messageHeaders, the DB view, the folder view...
relate to each other. I know there's already interface diagrams on MXR,
but I think a hand-made diagram would be much more useful.

One big disappointment to me was the fact that STEEL (and, by the way,
FUEL) seems to be completely abandoned. I was hoping for a real
"standard library" for Thunderbird extensions, providing wrappers for
extremely common actions such as getting the contents of a mail, marking
a message as read... However, no such thing exists. The only useful
resource is MDC [3] which is extremely sparse.

<!-- //rant
To go on with the "mark message as read" example, nowhere is it
specified that nsIMsgDbHdr :: markRead() is useless for IMAP accounts
and that the right way to do that is to create a nsIArray, to populate
it with the nsIMsgDbHdr and then to call msgHdr.folder.markMessagesRead.
But, wait, how do I create a nsIArray myself ? Well... You see my point
:): we could use some wrappers here.

There also seems to be some overlap between what is being rewritten and
what is legacy code. That's normal but it can get confusing sometimes.
For instance, there exist both GetMsgFolderFromUri and
MailUtils.getFolderForURI. But, look, there's this wonderful
nsIFolderLookupService :: getFolderById ! [4] Wait, there's an interface
but no implementation ? Oh sure, that's bug 441437... the implementation
was there before but was backed out. An "official reference" would be
helpful there.

The ideal solution would be to have some .jsm that offers helpers for
the most common actions. I've been doing this more or less for my
extensions, but I think there should be some "official" way of doing
this. If this is too hard to maintain, I think updating the Thunderbird
how-to list on MDC would be a nice alternative. I plan to do some of it
myself, but I'm no Thunderbird developer and I might not always write
the best solution.

Some other functions I've been dreaming of: messageIsDraft(nsIMsgDbHdr),
messageIsArchive, messageIsSent (instead of re-writing const
nsMsgFolderFlag_... again and again), getMessageBody(bool wantHTML),
msgHdrToNeckoURL, replyTo(msgHdr), replyToAll, replyToList,
senderNameToNameAndEmailAddress (separates the name from the email
address in "John Doe <john at>")... Of course I've found how to do
that and many of these functions are two-liners, but I'd rather have at
least code samples or pre-built wrappers that don't require me to jump
from file to file on MXR to get to the right code.

*II. Some more specific remarks about Gloda*

(1) I needed to display messages using the regular display code. That
is, using the HTML if the message has HTML, but stripped of all JS, with
images blocked according to the global security policy. I first thought
that Gloda would offer a wrapper for that. But all I could find was
GlodaMessage::coerceBodyToPlaintext. That was pretty useful, but I found
it odd that, given that all the MIME structure was built, no such
equivalent was available for the HTML contents. I wrote a custom
function that recursively walks down the GlodaMessage's .parts and
returns whatever has contentType "text/html" and looks like a "message
body". However, JS is not stripped, images are not blocked... I finally
resorted to copying nsMessenger.cpp's behavior using loadURI,
nsIMarkupDocumentViewer and nice gory details such as
hintCharacterSetSource on the contentViewer.

It's working fine but I still haven't found the "right way" to get rid
of the header block "From: / Date: / etc." that is automatically
prepended when the message is streamed to the <iframe> (yes, I'm using
an <iframe>, I wish I weren't but that's all I found). I'm currently
appending "?header=quotebody" to the URL but it's not meant for that
purpose. That's the kind of situation where I wish there was some
pre-built wrapper around this, because I'm a bit reluctant to spend even
more evenings digging through MXR just to get this done.

(2) Concerning my specific needs, I need to quickly get the
MessagesCollection from a nsIMsgDbHdr. That's currently a two-part
process, where I first use getMessageCollectionForHeaders to get the
GlodaMessage corresponding to my nsIMsgDbHdr. I then query that
GlodaMessage using GlodaMessage.conversation.getMessagesCollection.
That's completely sub-optimal, and I could really use a
"getConversationsForHeaders". I'm comfortable with nesting function ()
{}s but I wish this were a more direct process.

To be even more specific, Gloda conversations respect "strict
threading". This means that when my extension is used in conjunction
with mail.strict_threading set to false, I need to repeat the two-part
process for each message in the "false thread" because Gloda won't
relate these messages together in a GlodaConversation. The Gloda logic
is perfectly fine, it's nice to have strong semantics, but once again
I'd need a getConversation*s*ForHeader*s*.

(3) I also have some bugs I'd like to see fixed (more specifically bug
534449 and bug 538750, the latter being partly fixed by my extension),
but I'm pretty confident these will get resolved in time. I'd also like
to see bug 478167 fixed, but this probably isn't going to happen because
of limited resources.

(4) Some other things I'd like to see in Gloda:
- mimeMsgToContentSnippetAndMeta's meta part never seems to return the
author properly. Ideally, that would be a GlodaIdentity that corresponds
to the name stored in the Address Book.
- the ability to preformat a plain/text message (recognize *bold*,
_underscore_, email addresses, links, and others, plus blockquotes but
we've already been discussing this on bug 241197).
CC[";1"]::scanTXT already does that, but once
again, it took me ages to discover that component.
- the ability to make a difference between a forwarded message and a
"real" attachment (currently, both have .isRealAttachment set to true).

*III. Other remarks*

There are definitely more and more parts of the UI that use HTML (search
results, thread summaries). What a shame that functions such as
_mm_addClass, _mm_removeClass are defined locally and not made available
in a .jsm somewhere for extension developers! I partly used jQuery at
the beginning, but as I really was not satisfied (slows things down,
does not always play nice with XUL, spits tons of errors), I resorted to
more old-style DOM code. I'm unsure as to what is the best solution here.

*IV. Conclusion*

This was quite a long email (congrats if you read all the way down) but
I felt the need to discuss those many points with the team, as I think
it's important for extension developers to give feedback. I still
believe in Thunderbird which is why I'm trying to fill the gaps I
consider the more important (but that's subjective). However, although a
lot of progress has been made, the internals are not yet as good as they
could be. I really think some clear foundations need to be built to
leverage the potential for addons. There are a lot of things to explore
(I already have at least three other extensions in mind), but if
properly getting a message's body takes you three days when you're not
familiar with the code, that's going to discourage a lot of people.

Finally, if I sounded a bit harsh, I apologize in advance. Please take
this as a starting point for further discussion, not an angry rant. I
understand you're a bit short on resources and you don't always have the
time for building stable APIs, but I'm convinced that attracting
extension developers will bring the project more momentum and, in the
end, more contributors.

jonathan (:protz)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the tb-planning mailing list