Going to a message using the messageID

Talk about add-ons and extension development.
Post Reply
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Going to a message using the messageID

Post by user2018 »

Using JavaScript, I would like to go to the message that has a specific messageID. I know that it is possible to do this if you have the message's URI, by using:

var messenger = Cc["@mozilla.org/messenger;1"].createInstance(Ci.nsIMessenger);
var msgHdr = messenger.msgHdrFromURI(messageURI);
gFolderDisplay.selectMessage(msgHdr);

Is there an alternative for the cases when we don't have the URI of the message but we have its messageID?

Thanks a lot.
User avatar
DanRaisch
Moderator
Posts: 127187
Joined: September 23rd, 2004, 8:57 pm
Location: Somewhere on the right coast

Re: Going to a message using the messageID

Post by DanRaisch »

Moving to Thunderbird Support.
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: Going to a message using the messageID

Post by morat »

It is possible to find the same message id in multiple folders, like in the inbox and all mail folders in a google mail account.

Try these:

Code: Select all

// show msgUri of selected message
var msgHdr = gFolderDisplay.selectedMessage;
var msgUri = msgHdr.folder.getUriForMsg(msgHdr);
alert(msgUri);

Code: Select all

// select folder and message using msgUri
var msgUri = "imap-message://username%40gmail.com@imap.googlemail.com/INBOX#123";
var msgHdr = messenger.msgHdrFromURI(msgUri);
gFolderTreeView.selectFolder(msgHdr.folder);
gFolderDisplay.selectMessage(msgHdr);

Code: Select all

// show messageId of selected message
var msgHdr = gFolderDisplay.selectedMessage;
var messageId = msgHdr.messageId;
alert(messageId);

Code: Select all

// select message in current folder using messageId
var messageId = "123456789@example.org";
var folder = gFolderDisplay.displayedFolder;
var msgHdr = folder.msgDatabase.getMsgHdrForMessageID(messageId);
gFolderDisplay.selectMessage(msgHdr);
The following examples use a recursive function.

Code: Select all

// show all folders
function checkSubFolders(aFolder) {
  if (!aFolder.hasSubFolders) {
    return;
  }
  var enumerator = aFolder.subFolders;
  while (enumerator.hasMoreElements()) {
    var folder = enumerator.getNext().
      QueryInterface(Components.interfaces.nsIMsgFolder);
    allFolders.push(folder.URI);
    checkSubFolders(folder);
  }
}
var am = Components.classes["@mozilla.org/messenger/account-manager;1"].
  getService(Components.interfaces.nsIMsgAccountManager);
var allServers = am.allServers;
var numServers = allServers.length;
var allFolders = new Array();
for (var i = 0; i < numServers; i++) {
  var server = allServers.
    queryElementAt(i, Components.interfaces.nsIMsgIncomingServer);
  checkSubFolders(server.rootFolder);
}
var data = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">';
data += "<html><head><title>Example</title>";
data += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
data += "</head><body><pre>" + allFolders.join("\n") + "</pre></body></html>";
document.getElementById("tabmail").openTab("contentTab", {
  contentPage: "data:text/html;charset=utf-8;base64," + btoa(data),
  background: false,
});

Code: Select all

// select folder and message using messageId
var messageId = "123456789@example.org";
function checkSubFolders(aFolder) {
  if (!aFolder.hasSubFolders) {
    return;
  }
  var enumerator = aFolder.subFolders;
  while (enumerator.hasMoreElements()) {
    var folder = enumerator.getNext().
      QueryInterface(Components.interfaces.nsIMsgFolder);
    var msgHdr = folder.msgDatabase.getMsgHdrForMessageID(messageId);
    if (msgHdr) {
      gFolderTreeView.selectFolder(msgHdr.folder);
      gFolderDisplay.selectMessage(msgHdr);
      alert("Click OK to continue.");
    }
    checkSubFolders(folder);
  }
}
var am = Components.classes["@mozilla.org/messenger/account-manager;1"].
  getService(Components.interfaces.nsIMsgAccountManager);
var allServers = am.allServers;
var numServers = allServers.length;
for (var i = 0; i < numServers; i++) {
  var server = allServers.
    queryElementAt(i, Components.interfaces.nsIMsgIncomingServer);
  checkSubFolders(server.rootFolder);
}
P.S.

It's best to post such topics in the Extension Development forum.
Last edited by morat on October 3rd, 2018, 8:00 am, edited 2 times in total.
User avatar
DanRaisch
Moderator
Posts: 127187
Joined: September 23rd, 2004, 8:57 pm
Location: Somewhere on the right coast

Re: Going to a message using the messageID

Post by DanRaisch »

Moving to Extension Development as recommended by morat.
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Re: Going to a message using the messageID

Post by user2018 »

Thank you very much for this great suggestion. I tried it but, when it starts traversing folders I eventually get the following exception:

Exception: [Exception... "Component returned failure code: 0x80550005 [nsIMsgFolder.msgDatabase]" nsresult: "0x80550005 (<unknown>)" location: "JS frame :: Scratchpad/1 :: checkSubFolders :: line 30" data: no]

As I added some "alert" for debugging purposes, line in my code 30 is:

var msgHdr = folder.msgDatabase.getMsgHdrForMessageID(messageId);

Any ideas about what could be wrong?
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: Going to a message using the messageID

Post by morat »

I don't know the best way to deal with an outdated msf condition.

Error: uncaught exception... 0x80550005 [nsIMsgFolder.msgDatabase]
http://bugzilla.mozilla.org/show_bug.cgi?id=493429

Try this:

Code: Select all

// select folder and message using messageId
var messageId = "123456789@example.org";
function checkSubFolders(aFolder) {
  if (!aFolder.hasSubFolders) {
    return;
  }
  var enumerator = aFolder.subFolders;
  while (enumerator.hasMoreElements()) {
    var folder = enumerator.getNext().
      QueryInterface(Components.interfaces.nsIMsgFolder);
    var msgHdr = null;
    try {
      msgHdr = folder.msgDatabase.getMsgHdrForMessageID(messageId);
    } catch (e) {
      Components.utils.reportError(e);
      Services.console.logStringMessage("Debug: " + folder.URI);
    }
    if (msgHdr) {
      gFolderTreeView.selectFolder(msgHdr.folder);
      gFolderDisplay.selectMessage(msgHdr);
      alert("Click OK to continue.");
    }
    checkSubFolders(folder);
  }
}
var am = Components.classes["@mozilla.org/messenger/account-manager;1"].
  getService(Components.interfaces.nsIMsgAccountManager);
var allServers = am.allServers;
var numServers = allServers.length;

MailUtils.discoverFolders(); // make sure folder tree is initialized

for (var i = 0; i < numServers; i++) {
  var server = allServers.
    queryElementAt(i, Components.interfaces.nsIMsgIncomingServer);
  checkSubFolders(server.rootFolder);
}
Maybe try to force a reparse somehow.

Similar thread: http://forums.mozillazine.org/viewtopic ... &t=3041079
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Re: Going to a message using the messageID

Post by user2018 »

Thanks a lot! This is really very useful. I tried the code in another computer and it works, even without the extra code for reparsing. So I think that I should assume that in the first computer I was using there are problems with some .msf files, which could also be probably solved by clicking on the folder and selecting "Properties"->"Repair Folder" (clicking) or by deleting the .msf files and let Thunderbird rebuild them. Did I interpret the problem correctly?

I found another minor issue. I was trying to avoid searching in special/virtual folders such as saved search folders by adding this:

if (aFolder.getFlag(MSG_FOLDER_FLAG_VIRTUAL) == true) {
return;
}

However, I get an error that the MSG_FOLDER_FLAG_VIRTUAL symbol cannot be found. Do I need to declare it or is there any way to import/include the nsMsgFolderFlags.h? This is probably a very simple question, but I am having a hard time to find an answer, as in the sample code I found they seem to be using the constant MSG_FOLDER_FLAG_VIRTUAL directly in the code. Adding the following line in my code solves the problem, but it does not seem to be the right way to do it:

var MSG_FOLDER_FLAG_VIRTUAL = 0x0020;

Thank you.
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: Going to a message using the messageID

Post by morat »

I don't know if you need to do a folder repair. Normally, a user selection of a folder would force a reparse.

Try these:

Code: Select all

var folder = gFolderDisplay.displayedFolder;
if (folder.getFlag(Components.interfaces.nsMsgFolderFlags.Virtual)) {
  alert("folder is a virtual folder");
} else {
  alert("folder is not a virtual folder");
}

Code: Select all

var folder = gFolderDisplay.displayedFolder;
if (folder.flags & Components.interfaces.nsMsgFolderFlags.Virtual) {
  alert("folder is a virtual folder");
} else {
  alert("folder is not a virtual folder");
}

Code: Select all

var folder = gFolderDisplay.displayedFolder;
var trashFolder = folder.rootFolder.
  getFolderWithFlags(Components.interfaces.nsMsgFolderFlags.Trash);
alert(folder.URI + "\n" + trashFolder.URI);
Reference
http://developer.mozilla.org/en/XPCOM_I ... IMsgFolder
http://dxr.mozilla.org/comm-esr60/sourc ... rFlags.idl

Unfortunately, the docs aren't that great so you need to search the source. I like to unzip the omni.ja file and do a search...

Code: Select all

findstr /spc:"getFlag" *
Findstr command
http://ss64.com/nt/findstr.html

Sometimes searching the omni.ja file is easier than seaching the source online.

Search "getFlag" in Thunderbird 60
http://dxr.mozilla.org/comm-esr60/search?q=getFlag
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Re: Going to a message using the messageID

Post by user2018 »

Thanks a lot. This looks really nice. However, now I get a similar component failure error when I try to go to a message directly using the URI of the message:

Exception: [Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIMessenger.msgHdrFromURI]" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: Scratchpad/1 :: <TOP_LEVEL> :: line 62" data: no]

I tried to solve it with a similar solution, but I keep getting the same error:

var messenger = Cc["@mozilla.org/messenger;1"].createInstance(Ci.nsIMessenger);
var msgHdr = null;
try {
msgHdr = messenger.msgHdrFromURI(messagePointer);
} catch (e) {
Components.utils.reportError(e);
Services.console.logStringMessage("Debug: " + messagePointer);
}
if (msgHdr) {
gFolderTreeView.selectFolder(msgHdr.folder);
gFolderDisplay.selectMessage(msgHdr);
}

Any ideas? Thank you very much.
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: Going to a message using the messageID

Post by morat »

Is the messagePointer a message URI or a folder URI? I get the same error with the following code.

Code: Select all

var msgHdr = gFolderDisplay.selectedMessage;
var msgUri = msgHdr.folder.getUriForMsg(msgHdr);
msgHdr = messenger.msgHdrFromURI(msgUri);
msgHdr = messenger.msgHdrFromURI(msgHdr.folder.URI); // error
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Re: Going to a message using the messageID

Post by user2018 »

In my case, it is a message URI.
Post Reply