Closed Bug 490042 Opened 13 years ago Closed 13 years ago

Provide hooks so extensions can easily modify the message header view


(Thunderbird :: Message Reader UI, defect, P3)



(Not tracked)

Thunderbird 3.0b4


(Reporter: benjamin.lerner, Assigned: dmosedale)


(Keywords: dev-doc-needed, Whiteboard: [no l10n impact])


(1 file)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/2009040821 Firefox/3.0.9
Build Identifier: 

(Spun off from gerv's blog, bug 408370, and

Currently, there is no easy way for extensions to customize what appears in the message header (either expanded or collapsed), as there is too tight a dependency between reading the libmime headers and displaying them.  Copying from the message thread:

(Ben Lerner wrote)
I tried manually tracing through the code (on mxr) to figure out what's happening as a message gets displayed, and found 


So...could the ordering in onEndHeaders be reversed, to allow extensions
to access and maybe modify the currentHeaderData object? That would be
sufficient to enable Gerv's suggestion and other related ideas. Or is
there some subtle invariant that would break if that were permitted?

(Andrew Sutherland wrote)
Dan Mosedale has been interacting with the message reader code the most as of late, so he is probably most qualified to speak on it...

Although invariant is probably way too strong a word for it, I think a reasonable approach might be to introduce an additional call prior to onEndHeaders with the semantics you suggest.

Ideally, the message reader would have explicit extension points that are 'supported' in that they aren't likely to break, are intended to let multiple extensions play well together, and that we will try not to break.  I don't think the message reader is there right now, and I fear it won't get there before TB3.0... as such, it seems reasonable to add such a method for your use case, as long as everyone understands it's a stop-gap measure (that will probably live a long and full life.) 

Reproducible: Always
This should be a very tiny amount of work and is high-leverage.  Setting as blocking and taking.
Assignee: nobody → dmose
Ever confirmed: true
Flags: blocking-thunderbird3+
Target Milestone: --- → Thunderbird 3.0b3
Just wondering about the status of the new header layout, compact header etc.
Y've done some coordination .. but lost track .. is there 'one' good place for tracking the status?
The best place for tracking status is probably Bugzilla.  Stuff that's marked as blocking-thunderbird3+ is likely to make Tb3, anything else is relatively unlikely to happen in that timeframe.
Priority: -- → P3
Target Milestone: Thunderbird 3.0b3 → Thunderbird 3.0b4
Whiteboard: [no l10n impact]
Assignee: dmose → nobody
Component: Mail Window Front End → Message Reader UI
QA Contact: front-end → message-reader
Assignee: nobody → dmose
Attached patch patch, v1Splinter Review
Add support to optional onBeforeShowHeaderPane method on gMessageListeners objects.
Attachment #397816 - Flags: review?(philringnalda)
Keywords: dev-doc-needed
Whiteboard: [no l10n impact] → [no l10n impact] [has patch; needs review]
Attachment #397816 - Flags: review?(philringnalda) → review+
Comment on attachment 397816 [details] [diff] [review]
patch, v1

>+ * Other components may listen to on start header & on end header notifications
>+ * for each message we display to do that you need to add yourself to our

Needs some run-on sentence surgery: I'd say "we display: to do that" because I love colons, but "we display. To do that" would work, too.
This looks like what I needed, thanks :)  I'll have cycles in two weeks or so (internship ending, then vacation) to revive the extension I was playing with and try to use this patch, and see if it's as flexible as I'd hoped...  If it works, I'll post the code for potential use as an example in the to-be-written dev docs.
Nit fixed and pushed:

Help with sample code for the docs would be great, Ben!  Thanks for the offer.
Closed: 13 years ago
Resolution: --- → FIXED
Whiteboard: [no l10n impact] [has patch; needs review] → [no l10n impact]
I'm working on some sample code, in a separate email thread with Jennifer Zickerman and David Ascher's.  The tricky bit I've run into is wanting to use a gloda query to get some contact information from the database (query == async) while in the event handler (handler == sync).  Naturally, this doesn't work very well :(  When I come up with a decent solution, I'll post that code...
That is unfortunate.  Just to get a better idea of exactly what you're trying to do, a link to your current code would be interesting to look at...
(cribbed from the email thread with Jennifer and David -- I don't have a clean .xpi yet to attach)

The extension I have in mind is basically a "Do something smart with autogenerated emails" extension.  So for instance, if I get a message saying "John Doe sent you a message on Facebook", with a from field of "<no-reply!@#%^> or something like that, I want to extract "John Doe", look that name up, find the contact, and replace the from field with that contact.  I'm well aware that I don't want to be editing the underlying .msf file, so instead I just want to revise the data used by the UI.  Here goes:  Assume I've set up a listener to run the following code:

function onBeforeShowHeaderPane() {
 var subjText = currentHeaderData.subject.headerValue;
 try {
   // 1) Find the name
   var senderRx = /^(.*) sent you a message on Facebook/;
   var senders = subjText.match(senderRx);
   var sender = senders[1];
   alert("Found sender: " + senders.toSource());

   // 2) Set up the query
   let query = Gloda.newQuery(Gloda.NOUN_CONTACT);; 
   // 3) Set up the listener
   let myListener = {
     onItemsAdded: function (aItems, aCollection) {},
     onItemsModified: function (aItems, aCollection) {},
     onItemsRemoved: function (aItems, aCollection) {},
     onQueryCompleted: function myListener_onQueryCompleted(aCollection) {
       try {
         // 5) If there is a unique contact & identity with that name, extract its first identity and patch it into the header.
         if (aCollection.items.length > 1) {
           alert("More than one contact by name '" + sender + "': " + aCollection.items.length + aCollection.items);
         } else if (aCollection.items.length == 0) {
           alert("No contacts with name '" + sender + "': " + aCollection.items.length + aCollection.items);
         let contact = aCollection.items[0];
         if (contact.identities.length > 1) {
           alert("Contact '" + + "' has multiple identities");
         sender = '"' + sender + '" <' + contact.identities[0].value + '>';
         currentHeaderData.from.headerValue = sender;
         if ("reply-to" in currentHeaderData)
           currentHeaderData["reply-to"].headerValue = sender;
       } catch (e) {
         alert("onQueryCompleted failed: " + e);
   try {
      // 4) Trigger the query
     let collection = query.getCollection(myListener);
   } catch (e) { alert("Something went wrong: " + e); }
 } catch (e) {

But here's the problem: The call to getCollection (step 4) is asynchronous, which means that the onBeforeShowHeaderPane event handler terminates before the query completes.  At which point, it's too late to modify the currentHeaderData any further. 

David pointed out that even if this worked as I intended, I'd only affect the header, not e.g. the thread pane, because the thread pane is tied tightly to the msf.  But still, O keepers of the message header: Now that I can modify the data in the header, how can I do anything non-trivial (e.g. gloda) with it? :)

I didn't mean to fork this discussion into both an email thread and this bug. :(  So if this discussion is better served offline, with only results/suggestions posted to this thread, then I'll loop interested folks into the email thread instead...
(In reply to comment #10)
> I didn't mean to fork this discussion into both an email thread and this bug. newsgroup / mailing list is the best place for such discussion.
You need to log in before you can comment on or make changes to this bug.