Archive a message and then get its URI

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

Archive a message and then get its URI

Post by user2018 »

I am using this JavaScript code to obtain the URI of a message selected:

var msgHdr = gFolderDisplay.selectedMessage;
var msgUri = msgHdr.folder.getUriForMsg(msgHdr);

The problem with this is that the URI changes once the message is archived (as the folder where the message is stored changes). So I have to manually archive the message, find the message in the destination folder, select it, and then execute the previous code in order to have the final URI. I would like to avoid all this process. Is there any way to perform the archiving (i.e., emulate that the user clicked on the "Archive" button) and then retrieve the URI automatically? It would be something like this:

var msgHdr = gFolderDisplay.selectedMessage;
var msgUri = magicMethodThatArchivesTheMessageAndReturnsItsURIonceArchived(msgHdr)

I'm confused about how magicMethodThatArchivesTheMessageAndReturnsItsURIonceArchived could be implemented.

Any idea would be very welcome!
morat
Posts: 6421
Joined: February 3rd, 2009, 6:29 pm

Re: Archive a message and then get its URI

Post by morat »

I can't get the new messageKey from the archiver object.

I tried using the nsIMsgFolderNotificationService listener, but it doesn't work.

Reference (comm-release is not available)
http://searchfox.org/comm-central/searc ... edMessages
http://searchfox.org/comm-central/sourc ... chiver.jsm
http://searchfox.org/comm-central/sourc ... ersion.txt

Testing in error console...

Code: Select all

(function () {

  console.log("old messageKey: " + gFolderDisplay.selectedMessage.messageKey);

  var listener = {
    msgAdded: function (aMsg) {
      // MailServices.mfn.removeListener(listener);
      console.log(aMsg);
    },
    itemEvent(aItem, aEvent, aData, aString) {
      // MailServices.mfn.removeListener(listener);
      console.log(aItem);
      console.log(aEvent);
    },
    msgKeyChanged: function (aOldMsgKey, aNewMsgHdr) {
      // MailServices.mfn.removeListener(listener);
      console.log(aOldMsgKey);
      console.log(aNewMsgHdr);
    },
  };
  MailServices.mfn.addListener(listener,
    MailServices.mfn.msgAdded | MailServices.mfn.itemEvent | MailServices.mfn.msgKeyChanged);

  var archiver = new MessageArchiver();
  archiver.folderDisplay = gFolderDisplay;
  archiver.msgWindow = msgWindow;
  archiver.oncomplete = function () {
    console.log(archiver);
    console.log(archiver._currentBatch.archiveFolderURI); // gmail.com IMAP All Mail folder
    console.log(archiver._currentBatch.messages[0].messageKey); // old messageKey
  };
  archiver.archiveMessages(gFolderDisplay.selectedMessages);

})();

Code: Select all

(function () {

  // show folderUri and messageId and msgUri of selected message
  var msgHdr = gFolderDisplay.selectedMessage;
  var msgUri = msgHdr.folder.getUriForMsg(msgHdr);
  console.log(msgHdr.folder.URI);
  console.log(msgHdr.messageId);
  console.log(msgUri);

})();

Code: Select all

(function () {

  // show folderUri of archive folder
  var folder = gFolderDisplay.displayedFolder;
  var archiveFolder = folder.rootFolder.
    getFolderWithFlags(Components.interfaces.nsMsgFolderFlags.Archive);
  console.log(archiveFolder.URI);

})();

Code: Select all

(function () {

  // show msgUri using messageId and folderUri
  var messageId = "123456789@example.org";
  var folderUri = "imap://abracadabra%40gmail.com@imap.googlemail.com/[Gmail]/All Mail";
  var folder = MailUtils.getExistingFolder(folderUri);
  var msgHdr = folder.msgDatabase.getMsgHdrForMessageID(messageId);
  var msgUri = msgHdr.folder.getUriForMsg(msgHdr);
  console.log(msgUri);

})();
Similar thread: http://forums.mozillazine.org/viewtopic ... &t=3041933

ThunderKdB search results
http://github.com/cleidigh/ThunderKdB/s ... lename:.js
http://github.com/cleidigh/ThunderKdB/s ... lename:.js
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Re: Archive a message and then get its URI

Post by user2018 »

Thank you for all the ideas. I am trying to find a solution to the problem.

In one of my attempts, I stumped at the following problem. The archiving of the message is asynchronous. Is there any way to block the code and wait for the oncomplete function to execute before continuing the execution? I tried to set a variable "end" to true when executing oncomplete and test its value with a loop, but it seems there is no sleep method that I could execute between sleeps (a busy loop with no sleep freezes TB, as expected).
morat
Posts: 6421
Joined: February 3rd, 2009, 6:29 pm

Re: Archive a message and then get its URI

Post by morat »

The above code works for me with a selected message in the Inbox folder.

Code: Select all

(function () {

  var msgHdr = gFolderDisplay.selectedMessage;
  var msgUri = msgHdr.folder.getUriForMsg(msgHdr);
  var messageId = msgHdr.messageId;
  var archiveFolder = msgHdr.folder.rootFolder.
    getFolderWithFlags(Components.interfaces.nsMsgFolderFlags.Archive);
  console.log(msgUri);
  console.log(messageId);
  console.log(archiveFolder.URI);

  var archiver = new MessageArchiver();
  archiver.folderDisplay = gFolderDisplay;
  archiver.msgWindow = msgWindow;
  archiver.oncomplete = function () {
    var archiveMsgHdr = archiveFolder.msgDatabase.getMsgHdrForMessageID(messageId);
    var archiveMsgUri = archiveMsgHdr.folder.getUriForMsg(archiveMsgHdr);
    archiveFolder.msgDatabase = null; // don't leak
    console.log(archiveMsgUri);
    setTimeout(function () {
      gFolderTreeView.selectFolder(archiveFolder);
      gFolderDisplay.selectMessage(archiveMsgHdr);
    }, 2000);
  };
  archiver.archiveMessages(gFolderDisplay.selectedMessages);

})();
After running the code, I checked the messageId of the selected message in the All Mail folder.

Code: Select all

gFolderDisplay.selectedMessage.messageId;
Are you asking how to force an asynchronous call to behave synchronously?

Asynchronous JavaScript
http://developer.mozilla.org/docs/Learn ... ynchronous
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Re: Archive a message and then get its URI

Post by user2018 »

Thank you very much for this code! This seems very useful and promising.

However, with most messages I get an error executing that code:

Exception: TypeError: archiveFolder is null

In other words, the execution of the line to initialize the variable archiveFolder seems to return null. However, there is an archive folder, as I can click on the "Archive" button and the message goes to my archive folder (in this case, Archives -> ARCHIVED - Local Folders).

Regarding the other question, yes I was querying about how to make an asynchronous call synchronous. I looked a the URL that you provided and I concluded that the trick was to use await. However, I tried with:

await archiver.archiveMessages(gFolderDisplay.selectedMessages);

but this leads to an error:

Exception: SyntaxError: await is only valid in async functions and async generators

Thanks a lot for any suggestion.
morat
Posts: 6421
Joined: February 3rd, 2009, 6:29 pm

Re: Archive a message and then get its URI

Post by morat »

user2018 wrote:Local Folders
Try this:

Code: Select all

(function () {

  var accountManager = Components.classes["@mozilla.org/messenger/account-manager;1"].
    getService(Components.interfaces.nsIMsgAccountManager);
  var archiveFolder = accountManager.localFoldersServer.rootFolder.
    getFolderWithFlags(Components.interfaces.nsMsgFolderFlags.Archive);
  console.log(archiveFolder.URI);

})();
user2018
Posts: 196
Joined: September 23rd, 2018, 11:07 am

Re: Archive a message and then get its URI

Post by user2018 »

Thank you very much. This avoids the previous error but a new one is shown in the console:

TypeError: archiveMsgHdr is null

I see that probably the problem is that the archived folder retrieved is "mailbox://nobody@Local%20Folders/ARCHIVED" (this is the text shown in the console, but it should be "mailbox-message://nobody@Local%20Folders/ARCHIVED/2020/2020-02".

Any further ideas?

I still also have the problem of how to make the main code wait until the archiving of the message has completed (end of the execution of archiver.oncomplete).
morat
Posts: 6421
Joined: February 3rd, 2009, 6:29 pm

Re: Archive a message and then get its URI

Post by morat »

If the msgHdr is null, then I guess the message isn't in the folder.

If the nsMsgFolderFlags.Archive flag doesn't work, then use the folder url.

Code: Select all

(function () {

  var archiveFolderUri = "mailbox://nobody@Local%20Folders/Archives/123/Whatever";
  var archiveFolder = MailUtils.getExistingFolder(archiveFolderUri);
  console.log(archiveFolder.URI);

})();
I'm only a hobbyist. Ask someone else about asynchronous programming. It's too hard for me to explain.
Post Reply