Sending a Message (Mailnews Exchange Support)

By | July 15, 2010

I can now send a message through Exchange server from my Thunderbird installation.

Perhaps it would be interesting to show how I hooked into the sending function in the user interface. I asked the usual suspects, and it was not clear to anyone that it could be done without adding backend hooks – which I would like to avoid as much as possible to increase my chances of getting some initial alphas of this released to work with existing TB 3.1 users.

It turned out to be fairly straight forward. In MsgComposeCommands.js there is an observer notification that occurs, called “mail:composeOnSend”. This occurs right before the UI is ready to call SendMsg on the nsIMsgCompose object gMsgCompose. So what I needed to do was to intercept that call, and implement my own version of SendMsg rather than the SMTP/Rfc822-focused standard C++ code. To do that, I create a new object when I receive the notification with the old object as its prototype, then include a custom SendMsg that only applies if the sending account is an Exchange server. The overlay code ends up looking like this (greatly simplified):

function observe(subject, topic, data) {
 // wrap the gMsgCompose object so that we can detect attempts to
 //  send using ews.
 let newCompose = new ewsCompose(gMsgCompose);
 gMsgCompose = newCompose;
}

// ewsCompose provides a wrapper around the compose object, so that we
//  can override functions.
function ewsCompose(oldCompose) {
 this.oldCompose = oldCompose;
 this.SendMsg = function ewsSendMsg
     (msgType, identity, currentAccountKey, msgWindow, progress) {
   if (incomingServer instanceof Ci.msqIEwsIncomingServer) {
     // sending using Exchange Web Services (details not shown)
     // ...
     ewsCompose.sendMsg();
     return;
   }
   else
     return this.oldCompose.SendMsg
       (msgType, identity, currentAccountKey, msgWindow, progress);
 }
 this.__proto__ = oldCompose;
}

This seems to work just fine. It was a little tricky getting the compose code to believe that I had actually sent the message, so it could quit complaining of an unsent message. What I ended up doing in my “sending succeeded” callback is to add a few shutdown calls:

let ewsEventListener = {
  // msqIEwsEventListener implementation
  onEvent: function onEvent(aItem, aEvent, aData, aResult) {
    if (aEvent == 'StopRequest') {
      // ewsProgress was saved from the "progress" variable
      //   in nsMsgComposeCommands.js
      if (ewsProgress)
        ewsProgress.closeProgressDialog(aResult == Cr.NS_OK ? false : true);
      stateListener.ComposeProcessDone(aResult);
      MsgComposeCloseWindow(true);
    }
  }
}

With the ability now to send and receive messages, I’ve completed a single vertical pass through all of the key functionality. There are many, many details that I have passed over in the process. But it’s time to start thinking about what I would need to make work to get a usable alpha release of this, perhaps in about six weeks.