Mozilla.org Bug 11013 : dragging message/rfc822 attachments into folders

Intro
This page is a record of my work on Mozilla Bug 11013. The bug is an instance of a more general desire to treat attached message/rfc822 parts as full-fledged emails. 11013 specifically asks to be able to do copy them into a folder. Other related bugs want to do other full-fledged actions on them, like reply to them, forward them; etc. I believe that 11013 is crucial to the general problem : if you can copy a message/rfc822 to a folder, you get the other bugs' solutions "for free" : once they are copied to a new folder, you can reply, forward them, etc., without doing any additional bugfixing.
How does one introspect on XPCom objects inside the debugger? 2005-04-05 23:03:41
Merci à Nicolas Moreau 2005-03-30 08:47:12
An interesting article (in French) that I found when I googled DoRDFCommand. Seems to talk about RDF in the context of mail and folders, so should be a article tres utile !

Interesting that this french article seems to have the most "developer-authored" discussion that I have seen. It seems to show that mozilla/XPCOM/XUL are having more success finding a wide developer community in Europe than here in the US.

Get DoRDFCommand 2005-03-30 08:43:18
Track down location of DoRDFCommand.
PICKED URI : imap://test@hiro-tan.org/INBOX/test2 NewFolder : uri = imap://test@hiro-tan.org/INBOX/test2,name = dfsd ************************************************************ * Call to xpconnect wrapped JSObject produced this error: * [Exception... "'[JavaScript Error: "DoRDFCommand is not defined" {file: "chrome://tiny/content/dialogstart.js" line: 32}]' when calling method: [nsIDOMEventListener::handleEvent]" nsresult: "0x80570021 (NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS)" location: "<unknown>" data: yes] ************************************************************
More toying with simple dialogs 2005-03-29 01:57:20
<window id="config" xmlns:nc="http://home.netscape.com/NC-rdf#" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="Tiny Dialog" onload="onLoad();" onunload="onUnload();" > <script src="chrome://tiny/content/dialogstart.js"/> <stringbundle id="configBundle" src="chrome://global/locale/config.properties"/> </window>
dialogstart.js:
function NewFolder(name,uri) { dump("uri,name = " + uri + "," + name + "\n"); return; } function onLoad() { var dialog = window.openDialog( " chrome://tiny/content/newFolderDialog.xul", "", "chrome,titlebar,modal", {preselectedURI:null, dualUseFolders:true, okCallback:NewFolder}); }
However, the "OK" button doesn't become activated even after typing in a foldername, so need to figure out how that works.
Unexpectedly easy mail folder picker inclusion. 2005-03-21 00:12:30
With only a very minimal amount of tweaking (adding a namespace declaration, removing a couple of entities), I was able to add a folder picker to my tiny program! All I needed to do was cut and paste the <menulist>from chrome/messenger/content/messenger/msgFolderPickerOverlay.xul, and voila there it was...(see screenshot above).

Next : connect the folder picker actions to some action that tells us about the folder's URL. The idea isn't just to learn how to pick folders, but rather to understand how Messenger uses the picker's returned URL to create a folder.

The latest prototype from th4 skunk w0rkz 2005-03-17 20:55:55
OK, now I can write a XUL application that uses javascript to access the email account properties and gets the username for the 2nd account (which happens to be the IMAP account on my setup).. Sorry, you won't see anything useful because the javascript cannot run : you must copy the tiny.js to your chrome directory (see below).

To run it locally, you need to save both of these files to your chrome directory, for example

/usr/local/lib/mozilla-1.8b2/chrome/toolkit/content/global/
Then you can simply run :
mozilla chrome://global/content/tiny.xul

One interesting thing I discovered is that you can make this work :

mozilla http://hiro-tan.org/~ekoontz/bug11013/tiny.xul
but only if you already have run :
mozilla chrome://global/content/tiny.xul
Apparently there is some persistent javascript cache that is saving tiny.js so that it can be run again.

Which seems to me like possible a security risk..

Interesting official test programs 2005-03-10 02:31:24
Programdescriptioncomment
./TestOpen url filename Loads a URL using ::Open, writing it to a file Need to see if this works with IMAP or file-based folders.
./TestWordBreak and ./TestLineBreak Interesting just from an algorithmic case study perspective.
./TestStreamTransport Is mail folder communication done using streams?
./TestURLParser doesn't seem to work with "http://yahoo.com" as arg.
./TestProtocols
./nsIFileTest
./TestServMgr
./TestStreamLoader
Using CSS references to DOS your desktop 2005-03-06 15:35:31
Have you ever wanted to pop up an apparently invisible Mozilla window that completely disables your keyboard and mouse so that the only way to get control again is to SSH remotely and kill the shell from which you started Mozilla?

Me neither. But if you want to, here's a simple way : create a XUL file with this at the beginning : (note that the CSS file should attempt to refer to a CSS file, but should do so in a way that shows that you don't know how to refer to CSS files in XUL).

<?xml version="1.0"?> <?xml-stylesheet href="chrome://findfile/skin/asdfasdf.css" type="text/css"?> <window id="findfile-window" title="Find Files" orient="horizontal" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <vbox flex="1"> <description> Enter your search criteria below and select the Find button to begin the search. </description> <hbox> <label value="Search for:" control="find-text"/> <textbox id="find-text"/> </hbox> <hbox> <spacer flex="1"/> <button id="find-button" label="Find" default="true"/> <button id="cancel-button" label="Cancel"/> </hbox> </vbox> </window>
Semantic difference between resource:/ and chrome:// 2005-03-06 14:30:39
hiros-item(ekoontz)[/usr/local/lib/mozilla-1.8b2/chrome/findfile] $ find . -not -type d ./content/findfile.xul hiros-item(ekoontz)[/usr/local/lib/mozilla-1.8b2/chrome/findfile] $
mozilla -chrome resource:/chrome/findfile/content
This will simply popup a directory view of the directory /usr/local/lib/mozilla-1.8b2/chrome/findfile/content.
mozilla -chrome chrome://findfile/content
By contrast, this starts the findfile.xul application. The amazing thing is that this can happen even with no contents.rdf or relevant entries in installed-chrome.txt. Apparently chrome://findfile/content is "hardwired" to look for resource:/chrome/findfile/content/findfile.xul, and as far as I can tell, there is no way to cause chrome://findfile/content to open another file - you cannot move findfile.xul (for example, to findfile2.xul) and modify installed-chrome.txt and/or content.rdf to cause mozilla -chrome chrome://findfile/content to open findfile2.xul.

That doesn't bother me in itself - what I don't like is all of these complex files and syntax that doesn't seem to actually affect anything. (yes, of course, that's because I don't understand the meaning of these files and syntax...)

Two ways to start a XUL application 2005-03-05 12:06:32
Learning-by-doing with the findfile example from XULPlanet tutorial.
hiros-item(ekoontz)[/usr/local/lib/mozilla-1.8b2/chrome] $ find findfile -not -type d /usr/local/lib/mozilla-1.8b2/chrome/findfile/content/findfile/findfile.xul /usr/local/lib/mozilla-1.8b2/chrome/findfile/content/contents.rdf
mozilla -chrome chrome://findfile/content/findfile/findfile.xul
mozilla -chrome resource:/chrome/findfile/content/findfile/findfile.xul
The two ways seem to differ only in the syntax (slightly different ways to refer to the same file findfile.xul), but there are probably deeper semantic differences that I'm not aware of yet.

It appears that the following minimal contents.rdf doesn't have any significance (that is, you can remove it and the above commands still pop up the findfind.xul application) :

<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window id="findfile-window" title="Find Files" orient="horizontal" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <vbox flex="1"> <description> Enter your search criteria below and select the Find button to begin the search. </description> <hbox> <label value="Search for:" control="find-text"/> <textbox id="find-text"/> </hbox> <hbox> <spacer flex="1"/> <button id="find-button" label="Find" default="true"/> <button id="cancel-button" label="Cancel"/> </hbox> </vbox> </window>
Learning XUL from the XULPlanet tutorial. 2005-03-03 09:04:36
Looks like I'll need to understand the way the existing mailnews component interfaces with the relevant UI stuff (written XUL), before I can try to understand the former on their own...

This tutorial seems pretty good. The examples work pretty much as-is, and it looks like there is some detail on interfacing XUL and XPCOM. Creating/testing a little sample app :

mozilla -chrome resource:/chrome/findfile/content/findfile.xul
Learning XPCOM from the sample component. 2005-02-25 23:57:55
Slowly learning about XPCOM by creating a component. Started by copying the sample component and then removing everything and gradually adding things and trying it out with xpcshell. Put this "foo" component in my own CVS.
Learned how to setup xpcshell and nsISample 2005-02-14 08:42:52
I'm just going to ignore that transformiix stuff. IIRC transformix is the XSLT processor.
hiros-item(ekoontz)[/tmp/mozilla/xpcom/sample] $ export MOZILLA_FIVE_HOME=/usr/local/lib/thunderbird-0.6+/ hiros-item(ekoontz)[/tmp/mozilla/xpcom/sample] $ xpcshell Type Manifest File: /usr/local/lib/thunderbird-0.6+/components/xpti.dat +++ JavaScript debugging hooks installed. nsNativeComponentLoader: autoregistering begins. nsNativeComponentLoader: SelfRegisterDll(libp3p.so) Load FAILED with error: /usr/local/lib/thunderbird-0.6+/components/libp3p.so: undefined symbol: _ZTV18nsGetWeakReference nsNativeComponentLoader: SelfRegisterDll(libtypeaheadfind.so) Load FAILED with error: /usr/local/lib/thunderbird-0.6+/components/libtypeaheadfind.so: undefined symbol: _ZTV18nsGetWeakReference nsNativeComponentLoader: SelfRegisterDll(libtransformiix.so) Load FAILED with error: /usr/local/lib/thunderbird-0.6+/components/libtransformiix.so: undefined symbol: _ZTV18nsGetWeakReference nsNativeComponentLoader: autoregistering succeeded nsNativeComponentLoader: registering deferred (0) js> var sample = Components.classes["@mozilla.org/sample;1"].createInstance(); js> sample = sample.QueryInterface(Components.interfaces.nsISample); [xpconnect wrapped nsISample @ 0x8114428] js> sample [xpconnect wrapped nsISample @ 0x8114428] js> dump("sample = " + sample + "\n"); sample = [xpconnect wrapped nsISample @ 0x8114428] js> sample.value initial value js> sample.poke("foo"); js> sample.value foo js> sample.writeValue("hello"); hello foo foopy 5 GetValue 8 js>
A very useful documentation source 2005-02-09 00:51:56
http://docs.mandragor.org/files/Misc/Mozilla_applications_en/mozilla-chp-8-sect-2.html
Moving to xpcshell 2005-02-07 00:35:38
Decided to just write standalone .js scripts and figure out the mail API that way. It's just too slow and error prone to do it with Mozilla running inside gdb. I was trying to get a bit faster by just building thunderbird (below) but that's not going far enough.

Going to be using my simple "bug11013.js" scripts from my bug11013.jar (below).

Switched to thunderbird 2005-02-05 15:40:27
In an attempt to reduce the amount of detail needed to comprehend the code, I decided to rebuild as thunderbird :
./configure --enable-chrome-format=flat --prefix=/usr/local --enable-optimize=-g --enable-debug --enable-application=mail
Applied this patch to fix a freetype bug.
Deeper into the docShell stack 2005-02-05 02:18:13
nsDocShell.cpp:731 rv = InternalLoad(aURI, referrer, owner, inheritOwner, target.get(), nsnull, // No type hint postStream, headersStream, loadType, nsnull, // No SHEntry firstParty, nsnull, // No nsIDocShell nsnull); // No nsIRequest nsDocShell.cpp:5414 rv = DoURILoad(aURI, aReferrer, owner, aTypeHint, aPostData, aHeadersData, firstParty, aDocShell, aRequest); nsDocShell.cpp:5413 rv = DoURILoad(aURI, aReferrer, owner, aTypeHint, aPostData, aHeadersData, firstParty, aDocShell, aRequest); nsDocShell.cpp:5624 rv = DoChannelLoad(channel, uriLoader); nsDocShell.cpp:5773 rv = aURILoader->OpenURI(aChannel, (mLoadType == LOAD_LINK), this); nsURILoader.cpp:224 rv = aChannel->AsyncOpen(this, nsnull);
But, where is the AsyncOpen() method? What is the real type of aChannel?
Just what is a docshell? 2005-01-12 23:32:57
To recap from has come before, we are tracing the call stack that implements fetching messages and parts of messages (i.e. attachments) from a folder. Such fetched objects are represented as URIs, and a docshell seems to be the preferred method of fetching objects referred to by URIs.

Did a google search on docshell and came up with something very informative : "What the hell is the docshell?".

Fast way to get into docshell debugging:

export NSPR_LOG_MODULES="nsDocShell:5" export XPCOM_BREAK_ON_LOAD=msgdb /usr/local/bin/mozilla -g r shar docshell b nsDocShell.cpp:606
possible clue on getting LOG() to work 2005-01-09 01:08:02
I found this useful comment in the source code :
To put log messages in your programs, use the PR_LOG macro:
104 **
105 **     PR_LOG(<module>, <level>, (<printfString>, <args>*));
106 **
107 ** Where <module> is the address of a PRLogModuleInfo structure, and
108 ** <level> is one of the levels defined by the enumeration:
109 ** PRLogModuleLevel. <args> is a printf() style of argument list. That
110 ** is: (fmtstring, ...).
So, hopefully, to get the maximum amount of debugging output, we can do :
export NSPR_LOG_MODULES="all:5"
URLs : how to obfuscate them from debugging attempts. 2005-01-05 02:08:18
What a URL variable looks like in Mozilla code. For example, suppose you have an object called "channel" that contains a uri. This is how you can actually discover what the text of the uri is.
816 #ifdef PR_LOGGING 817 if (LOG_ENABLED()) { 818 nsCOMPtr<nsIURI> uri; 819 channel->GetURI(getter_AddRefs(uri)); 820 nsCAutoString spec; 821 uri->GetAsciiSpec(spec); 822 LOG(("nsURILoader::OpenURI for %s", spec.get())); 823 } 824 #endif
Easy.
non-mailbox protocol handling - what does it mean? 2005-01-05 02:08:05
Trying to figure out what this code is for :
nsLocalMailFolder.cpp:1723 if (!protocolType.LowerCaseEqualsLiteral("mailbox")) { mCopyState->m_dummyEnvelopeNeeded = PR_TRUE; nsParseMailMessageState* parseMsgState = new nsParseMailMessageState(); if (parseMsgState) { nsCOMPtr<nsIMsgDatabase> msgDb; mCopyState->m_parseMsgState = do_QueryInterface(parseMsgState, &rv); GetDatabaseWOReparse(getter_AddRefs(msgDb)); if (msgDb) parseMsgState->SetMailDB(msgDb); } }
nsMailboxService.cpp:117 : nsMailboxService::CopyMessage()
nsMailboxService.cpp:178 : nsMailboxService::FetchMessage()
getting very,very close to loading a message..could it be?
810 NS_IMETHODIMP nsURILoader::OpenURI(nsIChannel *channel, 811 PRBool aIsContentPreferred, 812 nsIInterfaceRequestor *aWindowContext) 813 { 814 NS_ENSURE_ARG_POINTER(channel); . . . 875 876 // now instruct the loader to go ahead and open the url 877 return loader->Open(channel); 878 }
Ah, but what is this mysterious "loader"? What's behind it's enigmatic "RawPtr*" disguise? Tune in next time to find out.
Deeper and deeper into copying messages.. 2005-01-03 00:47:48
Continuing the discussion of the copyMessage call stack, there are two final frame before calling the store-dependent copyMessage functionality; here is the first :
NS_IMETHODIMP nsMsgCopyService::CopyMessages(nsIMsgFolder* srcFolder, /* UI src folder */ nsISupportsArray* messages, nsIMsgFolder* dstFolder, PRBool isMove, nsIMsgCopyServiceListener* listener, nsIMsgWindow* window, PRBool allowUndo) { . . . rv = DoCopy(copyRequest); . . .
All the stuff that I've elided has to do with populating the copyRequest. So copyRequest seems to be a sequence of folder-messages pairs, where each pair is a folder and a list of messages for that folder that will be copied. (The destination was given to the copyRequest when its Init() was called :
rv = copyRequest->Init(nsCopyMessagesType, aSupport, dstFolder, isMove, listener, window, allowUndo);
) Then, we get to the last frame before calling the actual storage-dependent implementation:
nsMsgCopyService.cpp:286 rv = copyRequest->m_dstFolder->CopyMessages (copySource->m_msgFolder, copySource->m_messageArray, copyRequest->m_isMoveOrDraftOrTemplate, copyRequest->m_msgWindow, copyRequest->m_listener, PR_FALSE, copyRequest->m_allowUndo); //isFolder operation PR_FALSE
At last, here we are in the local folder-implementation of CopyMessages() :
nsLocalMailFolder.cpp:1655 NS_IMETHODIMP nsMsgLocalMailFolder::CopyMessages(nsIMsgFolder* srcFolder, nsISupportsArray* messages, PRBool isMove, nsIMsgWindow *msgWindow, nsIMsgCopyServiceListener* listener, PRBool isFolder, PRBool allowUndo)
Deep inside the "copy message" stack. 2005-01-02 23:43:35
First, how I set ddd to break in here :
(gdb) set env XPCOM_BREAK_ON_LOAD msgdb (gdb) r Starting program: /usr/local/lib/mozilla-1.8a6/mozilla-bin -venkman -chrome chrome://messenger/content/messenger.xul warning: Unable to find dynamic linker breakpoint function. GDB will be unable to debug shared library initializers and track explicitly loaded dynamic code. [Thread debugging using libthread_db enabled] [New Thread 16384 (LWP 16071)] Type Manifest File: /usr/local/lib/mozilla-1.8a6/components/xpti.dat +++ JavaScript debugging hooks installed. . lots of output deleted... . [New Thread 98310 (LWP 16083)] ++WEBSHELL == 6 ++DOMWINDOW == 6 vnk: } 9.377 sec window moved to offscreen position window moved to offscreen position window moved to offscreen position ...Loading module libmsgdb.so Program received signal SIGTRAP, Trace/breakpoint trap. [Switching to Thread 16384 (LWP 16071)] nsDll::BreakAfterLoad (this=0x816e328, nsprPath=0x90f71a8 "libmsgdb.so") at xcDll.cpp:429 (gdb) shar mail Reading symbols from /usr/local/lib/mozilla-1.8a6/components/libmailnews.so...done. Loaded symbols for /usr/local/lib/mozilla-1.8a6/components/libmailnews.so (gdb) b nsMsgDBView.cpp:2271 Breakpoint 1 at 0x419243b2: file nsMsgDBView.cpp, line 2271.
Notice that the copyService->CopyMessages is a virtual method of some kind that can be specialized to be any of : We will be going into detail next about how this last's CopyMessages function is implemented.
On the creation of objects with mimetype : text/x-moz-message. 2005-01-01 16:24:09
If we can figure out how to synthesize a text/x-moz-message object from a raw-text form of a message, we can simply allow attachments of type message/rfc822 to be converted to raw text, converted to a text/x-moz-message, and then to be dragged into the folder, just as folder messages can be dragged now.

The problem is that a "text/x-moz-message" object seems basically merely a reference to a certain message in a folder. (more precisely, it seems that it's a key in a flat-file database that is itself an index of the folder. So, we must first convert the message to a database entry (and thus into a folder) and THEN we can create a text/x-moz-message object that references this new database entry.

Turning message text into a message window : two implementations. 2004-12-31 01:53:29
There's two cases where a message can be displayed in a message window :
  1. A message stored in a folder.
  2. A message stored as an attachment to a message.
These two cases are implemented separately, with the second seeming to have been done more recently, in 2003, as a fix for bug 143565. Prior to this fix, an attached email (a message/rfc822 mime part) was simply shown as raw text, rather than being in a message window.

As an example of how these two cases' separate implementations differ, many of the buttons (Forward, Reply, etc) are disabled in the case of attachments. This has caused a lot of controversy in the related bugzilla entries.

We need to look at the code involved in this bug fix and note how its implementation of case 2 differs from the implementation of case 1. One way we'll distinguish these two cases is to call case 1's implementation "loadMessageByMsgKey()" and call case 2's implementation : "loadMessageByUrl()". These names refer to the javascript functions that constitute the essential difference between the two cases.

No updates till end of this month. 2004-12-23 11:14:00
On vacation for five days.
Enabling dragging over-generally.. 2004-12-22 01:17:31
These changes to messengerdnd.js allow us to drag an attachment over a folder and dropped. It's overgeneral because it allows any attachment to be dragged over and dropped without checking the mimetype. As I said earlier, I have to parse these mailbox://.. URLs to get the mimetype to allow only attachments of type message/rfc822 to be dragged and dropped over folders.
hiros-item(ekoontz)[/usr/local/lib/mozilla-1.8a6/chrome/messenger/content/messenger] $ diff -u /tmp/mozilla/mailnews/base/resources/content/messengerdnd.js . --- /tmp/mozilla/mailnews/base/resources/content/messengerdnd.js 2004-11-18 19:50:25.000000000 -0800 +++ ./messengerdnd.js 2004-12-22 01:07:29.801212208 -0800 @@ -46,7 +46,7 @@ function debugDump(msg) { // uncomment for noise - // dump(msg+"\n"); + dump(msg+"\n"); } function CanDropOnFolderTree(index, orientation) @@ -61,7 +61,9 @@ if (! dragSession) return false; - var flavorSupported = dragSession.isDataFlavorSupported("text/x-moz-message") || dragSession.isDataFlavorSupported("text/x-moz-folder"); + var flavorSupported = + dragSession.isDataFlavorSupported("text/x-moz-message") || + dragSession.isDataFlavorSupported("text/x-moz-folder"); var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); if (! trans) @@ -102,7 +104,12 @@ var sourceUri = dataObj.data.substring(0, len.value); if (! sourceUri) continue; - if (dataFlavor.value == "text/x-moz-message") + + dump("trying to drop obj with uri : " + sourceUri + " with mimetype : " + dataFlavor.value + "\n"); + + if ((dataFlavor.value == "text/x-moz-message") + || + (dataFlavor.value == "text/x-moz-url")) { sourceResource = null; var isServer = GetFolderAttribute(folderTree, targetResource, "IsServer"); @@ -114,13 +121,21 @@ // canFileMessages checks no select, and acl, for imap. var canFileMessages = GetFolderAttribute(folderTree, targetResource, "CanFileMessages"); if (canFileMessages != "true") - { + { debugDump("***canFileMessages == false\n"); return false; } - var hdr = messenger.messageServiceFromURI(sourceUri).messageURIToMsgHdr(sourceUri); - if (hdr.folder == targetFolder) - return false; + if (dataFlavor.value == "text/x-moz-message") { + var hdr = messenger.messageServiceFromURI(sourceUri).messageURIToMsgHdr(sourceUri); + if (hdr.folder == targetFolder) + return false; + } + else { // text/x-moz-url + // check if sourceUri points to an attached message/rfc822 + // if so, then.. + dump("GOT A TEXT/X-MOZ-URL.."); + flavorSupported = true; + } break; } else if (dataFlavor.value == "text/x-moz-folder") { @@ -282,8 +297,19 @@ rssService.subscribeToFeed(url, targetFolder, msgWindow); return true; } - else - return false; + else { + if (uri.schemeIs("mailbox")) { + dump("GOT HERE : A MAILBOX URL : " + uri + "\n"); + + // if it's a message/rfc822, then get the message text and + // turn it into some kind of message object... + + dropMessage = true; + } + else { + return false; + } + } } } else {
Here's some sample output from this:
trying to drop obj with uri : mailbox:///home/ekoontz/.mozilla/test/rcmagau1.slt/Mail/Local%20Folders/test?number=0&part=1.2&type=message/rfc822&filename=no more SPAM from this one.. no more SPAM from this one.. with mimetype : text/x-moz-url GOT A TEXT/X-MOZ-URL..trying to drop obj with uri : mailbox:///home/ekoontz/.mozilla/test/rcmagau1.slt/Mail/Local%20Folders/test?number=0&part=1.2&type=message/rfc822&filename=no more SPAM from this one.. no more SPAM from this one.. with mimetype : text/x-moz-url GOT A TEXT/X-MOZ-URL..BeginDragThreadPane
Compare the above (dragging attached message/rfc822 versus the following (dragging a folder message) :
selArray.length = 1 ID #0 = mailbox-message://nobody@Local%20Folders/test#0 trying to drop obj with uri : mailbox-message://nobody@Local%20Folders/test#0 with mimetype : text/x-moz-message trying to drop obj with uri : mailbox-message://nobody@Local%20Folders/test#0 with mimetype : text/x-moz-message
Of course, this is not enough to fix the bug : we need to actually convert the attachment's internal representation into a representation that can be appended to the folder. Currently we the following error output is seen when we drop the attachment on the folder; hopefully this will give us some clues about where to start looking next.
WARNING: NS_ENSURE_TRUE(NS_SUCCEEDED(rv)) failed, file nsMailboxService.cpp,line 541 WARNING: NS_ENSURE_TRUE(NS_SUCCEEDED(rv)) failed, file nsMailboxService.cpp,line 568 ************************************************************ * Call to xpconnect wrapped JSObject produced this error: * [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIMsgMessageService.messageURIToMsgHdr]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: chrome://messenger/content/messengerdnd.js:: DropOnFolderTree :: line 323" data: no] ************************************************************
Attached message dragging debug output 2004-12-20 09:12:54
Added the following line to CanDropOnFolderTree() :
dump("trying to drop obj with uri : " + sourceUri + " with mimetype : " + dataFlavor.value + "\n");
When I drag an attached message over a folder in the folder tree, I get the resulting output :
trying to drop obj with uri : imap://test@hiro-tan.org:143/fetch%3EUID%3E.INBOX.test2%3E4?part=1.2&type=message/rfc822&filename=no more SPAM from this one.. with mimetype : text/x-moz-url
Apparently we'll need to parse these URIs in order to extract that type=message/rfc822 so that we can return true in this case from CanDropOnFolderTree(). I assume there's some functionality for parsing URIs and extracting argument name/value pairs like this..
How drag and drop of attachments works 2004-12-19 15:11:13
messengerdnd.js:CanDropOnFolderTree() returns a boolean based on the dataFlavor.value. A normal (not attached) will have dataFlavor.value = text/x-moz-message :
if (dataFlavor.value == "text/x-moz-message") { sourceResource = null; var isServer = GetFolderAttribute(folderTree, targetResource, "IsServer"); if (isServer == "true") { debugDump("***isServer == true\n"); return false; } // canFileMessages checks no select, and acl, for imap. var canFileMessages = GetFolderAttribute(folderTree, targetResource, "CanFileMessages"); if (canFileMessages != "true") { debugDump("***canFileMessages == false\n"); return false; } var hdr = messenger.messageServiceFromURI(sourceUri).messageURIToMsgHdr(sourceUri); if (hdr.folder == targetFolder) return false; break;
More thoughts about last post 2004-12-19 13:57:28
When a new GUI element is added for each attachment, why is there no javascript callback added to the new element's attributes in displayAttachmentsForExpandedView()? Where is the callback to be found? (It's probably something like OpenAttachment()).
Attachments in messenger Posted 2004-12-19 12:29:36
By using the DOM Inspector tool, we can see gross message window structure simplified below; with attachments highlighted.
header info
Attachments:
id=attachmentList
(att1)(att2)(att3)
(att4)(att5)(att6)
Message Body display
The attachmentList is populated by the function msgHdrViewOverlay.js:displayAttachmentsForExpandedView(), shown below :
// For the currently displayed message, we store all the attachment data. When displaying a particular // view, it's up to the view layer to extract this attachment data and turn it into something useful. // For a given entry in the attachments list, you can ask for the following properties: // .contentType --> the content type of the attachment // url --> an imap, or mailbox url which can be used to fetch the message // uri --> an RDF URI which refers to the message containig the attachment // notDownloaded --> boolean flag stating whether the attachment is downloaded or not. . . . function displayAttachmentsForExpandedView() { var numAttachments = currentAttachments.length; if (numAttachments > 0 && !gBuildAttachmentsForCurrentMsg) { var attachmentList = document.getElementById('attachmentList'); for (index in currentAttachments) { var attachment = currentAttachments[index]; // we need to create a listitem to insert the attachment // into the attachment list.. var item = attachmentList.appendItem(attachment.displayName,""); item.setAttribute("class", "listitem-iconic"); item.setAttribute("tooltip", "attachmentListTooltip"); item.attachment = attachment; item.setAttribute("attachmentUrl", attachment.url); item.setAttribute("attachmentContentType", attachment.contentType); item.setAttribute("attachmentUri", attachment.uri); setApplicationIconForAttachment(attachment, item); } // for each attachment gBuildAttachmentsForCurrentMsg = true; } var expandedAttachmentBox = document.getElementById('expandedAttachmentBox'); expandedAttachmentBox.collapsed = numAttachments <= 0; }
currentAttachments is an array of attachment structures. This array is populated by the handleAttachment() function :
handleAttachment: function(contentType, url, displayName, uri, notDownloaded) { ... currentAttachments.push (new createNewAttachmentInfo(contentType, url, displayName, uri, notDownloaded)); ... }
There doesn't seem to be any calls to handleAttachment() in the chrome, but there seems to be a call in the components/mime.xpt component.
Sketch of solution Posted 2004-12-18 17:42:44
This is my summary of my proposal to implement the fix of this bug. Suppose someone wants to drag attached message/rfc822 part 'm' from a given message M.
  1. get URI(m) := the URI to the mime part that refers to m.
  2. read m into memory
  3. copy m to a temporary LocalMail folder T, call this new message m', which is the only message in T.
  4. URI(m') := (new path to m in folder T, as opposed to a path to an attachment in M)
  5. pass URI(m') as the source of the dragging action.
  6. When the user drops m on a folder F :
    1. Copy URI(m') using nsIMsgMessageService::CopyMessage() from T to F.
    2. Delete temporary folder T (which will also delete m').
Getting message information Posted 2004-12-18 17:42:52
Now I can retrieve a local message and get individual headers from it :
var gCurrentMessageUri = "mailbox-message://nobody@Local%20Folders/test#0"; . . var msgHdr = msgService.messageURIToMsgHdr(gCurrentMessageUri); dump("THE HEADER IS : " + msgHdr + "\n"); dump(" subject : " + msgHdr.subject + "\n"); dump(" author : " + msgHdr.author + "\n");
Now, I need to figure how to get the MIME structure for a message. I know that I can get an individual mime part with nsImsgMessageService::fetchMimePart, but how do I get the overall MIME structure (i.e., the MIME tree form) of the message?
Getting Started Posted 2004-12-18 17:43:02
  1. Using a functional version of mozilla, use Communicator to create a local folder called "test". Find a message M with an attached message/rfc822 part. Drag this message M into your "test" local folder.
  2. Check out mozilla source if you haven't already:
    export CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot cvs -z3 co mozilla
  3. Configure and make:
    ./configure --enable-chrome-format=flat --prefix=/usr/local --enable-optimize=-g --enable-debug --enable-application=suite make make install
  4. Unzip my little XUL bug diagnostics : bug11013.jar in /usr/local/lib/mozilla-1.8aX (where X is 6 currently, but will increase as the CVS tree changes).
  5. Add the following to your /usr/local/lib/mozilla-1.8aX/chrome/installed-chrome.txt :
    content,install,url,resource:/chrome/bug11013/content/bug11013/
  6. Run the following from a shell :
    mozilla -chrome "chrome://bug11013/content/bug11013.xul"
    Some output will be sent to the shell from the diagnostic's dump() calls. Hopefully you'll see things like :
    THE HEADER IS : [xpconnect wrapped nsIMsgDBHdr @ 0x82fc0d8] subject : [Fwd: no more SPAM from this one..] author : Eugene Koontz <ekoontz@hiro-tan.org>

All code written by me here is licenced under the GNU Public Licence.

All documents here are licenced under the GNU Free Document Licence.

Eugene Koontz
Valid HTML 4.01!
Last modified: Tue Apr 5 23:04:51 PDT 2005