Index: src/orca/scripts/apps/Thunderbird/script.py
===================================================================
--- src/orca/scripts/apps/Thunderbird/script.py	(revision 4029)
+++ src/orca/scripts/apps/Thunderbird/script.py	(working copy)
@@ -30,9 +30,11 @@
 import pyatspi
 
 import orca.orca as orca
+import orca.braille as braille
 import orca.debug as debug
 import orca.default as default
 import orca.input_event as input_event
+import orca.keybindings as keybindings
 import orca.orca_state as orca_state
 import orca.settings as settings
 import orca.speech as speech
@@ -85,6 +87,54 @@
 
         self.textArea = None
 
+    def setupInputEventHandlers(self):
+        """Defines InputEventHandler fields for this script that can be
+        called by the key and braille bindings.
+        """
+
+        Gecko.Script.setupInputEventHandlers(self)
+
+        self.inputEventHandlers["readMessageHeader"] = \
+            input_event.InputEventHandler(
+                Script.readMessageHeader,
+                # Translators, this command will cause Orca to present
+                # a given mail message header (e.g. To, From, Subject)
+                # in speech and in braille so that the user can obtain
+                # this information without having to leave the body of
+                # the message he/she is reading.
+                #
+                _("Speak and braille a message header."))
+
+    def getKeyBindings(self):
+        """Defines the key bindings for this script.
+
+        Returns an instance of keybindings.KeyBindings.
+        """
+
+        keyBindings = keybindings.KeyBindings()
+
+        headerKeys = [ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9" ]
+        for headerKey in headerKeys:
+            keyBindings.add(
+                keybindings.KeyBinding(
+                    headerKey,
+                    settings.defaultModifierMask,
+                    settings.ORCA_MODIFIER_MASK,
+                    self.inputEventHandlers["readMessageHeader"]))
+
+        # We need to prevent the Gecko live region bindings from stomping
+        # on the bindings to read the message headers.  Perhaps instead
+        # we should move the live region bindings out of Gecko and into
+        # a firefox-specific script??
+        #
+        geckoBindings = Gecko.Script.getKeyBindings(self)
+        for binding in geckoBindings.keyBindings:
+            if not keyBindings.hasKeyBinding(binding, typeOfSearch="keys") \
+               or not binding.keysymstring:
+                keyBindings.add(binding)
+
+        return keyBindings
+
     def getSpeechGenerator(self):
         """Returns the speech generator for this script.
         """
@@ -521,3 +571,62 @@
                 obj = obj.parent
 
         return None
+
+    def _getMessageHeaders(self):
+        frame = self.getTopLevel(orca_state.locusOfFocus)
+        headersScrollPane = None
+        for child in frame:
+            if child.getRole() == pyatspi.ROLE_SCROLL_PANE \
+               and child.childCount > 1:
+                headersScrollPane = child
+                break
+
+        if not headersScrollPane:
+            return []
+
+        headers = []
+        for i, child in enumerate(headersScrollPane):
+            if child.getRole() == pyatspi.ROLE_LABEL and child.name:
+                # Then child is a label for the header. The accessible
+                # that follows it is the displayed value.
+                #
+                label = child.name
+                if i < len(headersScrollPane) + 1:
+                    value = self.getDisplayedText(headersScrollPane[i + 1])
+                    headers.append([child.name, value])
+
+        return headers
+
+    def readMessageHeader(self, inputEvent):
+        """ Speak/braille a message header. Up to nine can be presented.
+
+        Arguments:
+        - inputEvent: if not None, the input event that caused this action.
+        """
+
+        i = int(inputEvent.event_string[1:])
+        headers = self._getMessageHeaders()
+        if i <= len(headers):
+            label, value = headers[i - 1]
+            header = label.strip() + " " + value.strip()
+            speech.speak(header)
+            braille.displayMessage(header)
+        elif len(headers):
+            # Translators: Orca has a feature to speak the message headers
+            # (e.g. To, From, Subject) for a given email message. This
+            # string is what Orca presents if the user tries this command
+            # but the desired header (e.g. the fifth header) could not be
+            # located. In this case, %d is the number of the message.
+            #
+            notFoundString = _("Message header number %d not found.") % i
+            speech.speak(notFoundString)
+            braille.displayMessage(notFoundString)
+        else:
+            # Translators: Orca has a feature to speak the message headers
+            # (e.g. To, From, Subject) for a given email message. This
+            # string is what Orca presents if the user tries this command
+            # but the headers could not be located at all.
+            #
+            notFoundString = _("Message headers not found.")
+            speech.speak(notFoundString)
+            braille.displayMessage(notFoundString)
