Closed Bug 567585 Opened 14 years ago Closed 11 years ago

TB3 fails to raise an error when it tries to save an attachment to write-protected directory.

Categories

(Toolkit :: Downloads API, defect)

defect
Not set
critical

Tracking

()

RESOLVED DUPLICATE of bug 928250

People

(Reporter: ishikawa, Assigned: ishikawa)

Details

(Keywords: dataloss)

Attachments

(3 files, 13 obsolete files)

5.37 KB, patch
Paolo
: review+
sdwilsh
: review+
Details | Diff | Splinter Review
220.02 KB, image/png
Details
31.90 KB, patch
Details | Diff | Splinter Review
User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729)
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.3a5pre) Gecko/20100520 Thunderbird/3.2a1pre

Originally, I was discussing this problem in Bug 429827
Download manager does not warn when its download location does not exist or is write protected

But, per a latest suggestion,
I am branching out with a limited bug case to this new bugzilla
entry so that a sharper focus on a limited scope of a very specific bug 
is discussed here.

I want to limit the discussion here only to TB3's behavior regarding
the saving of an attachment of an e-mail article, when the LEFT mouse
button is clicked twice on the attachment.

I am limiting the bug reporting of my experience under linux, but
I believe this is observed under windows, too. (But correct me if I am wrong.).


Reproducible: Always

Steps to Reproduce:

Steps re-produce. 
I write a summary of what goes wrong and how when we try to
save an attachment to an e-mail article to a write-protected directory.

Create directories for testing:

       mkdir /tmp/a-dir
       mkdir /tmp/b-dir
       mkdir /tmp/c-dir

       create an empty file "existing" in /tmp/a-dir, and make it unwritable.
       touch /tmp/a-dir/existing
       chmod a-w /tmp/a-dir/existing
       
       touch /tmp/b-dir/existing
       chmod a-w /tmp/b-dir/existing
       
       Make directory /tmp/b-dir and /tmp/c-dir unwritable.
       chmod a-w /tmp/b-dir
       chmod a-w /tmp/c-dir


Step 1: Choose an e-mail article with an attachment.

     In my case, I was testing "libc-2.7.so" as attachment. 

     Double LEFT-click on the attachment.

     "Would you like to save this file?" dialog appears. (the attachment
     is recognized as BIN file.)
     There are buttons.
     [Cancel] [Save]

Step 2: Press Save and choose the save directory.

     Depending on the target direcory, there are a few scenarios.

     case (a)  /tmp/a-dir
     	  EXPECTED: TB3 should save the attachment.

	  WHAT HAPPENS.: OK, we can save the attachment.

     case (b)  /tmp/a-dir  but use "existing" as the name of the saved
          attachement. Then press "Save" button.

	  EXPECTED: Since there is a file "existing", TB3 should offer
	  the warning about existing file being overwritten.  Then
	  again, TB3 should save the attachement.
	  (Even if the file is unwritable, the directory is writable.)
	  
	  WHAT HAPPENS: OK. Behaves as expected.

	  (Funny, under linux, "existing" doesn't appear in the file
	  selection box during saving. I can change the filename for
	  the saved attachment to "existing", and get the warning.  I
	  am not sure if this is related to the file being
	  write-proteced or not(?). As it turns out, under my
	  environment, the file chooser only lists the existing files
	  with the same suffix, i.e., ".so" as the attachment. If I
	  create /tmp/a-dir/existing.so, it shows up in the file
	  chooser initially.)

     case (c)  /tmp/b-dir

          EXPECTED: Since the directory is write protected, 
	  TB3 should fail and warns the user that the file could not
	  be saved. Ideally, it should then offer to let user select
	  another directory.

	  WHAT HAPPENS.: NG. TB3 fails to save the attachment, but
	  there is no visual feedback about the error with GUI, and
	  TB3 proceeds as if it succeeded.

     case (d) /tmp/b-dir, but use "existing" as the name of the saved
          attachement. Then press "Save" button.

	  EXPECTED: Since there is a file "existing", TB3 should offer
	  the warning about existing file being overwritten.  But then
	  again, TB3 should fail saving since the directory is
	  unwritable. Ideally, it should offer to let user select
	  another directory (and a name).

	  WHAT HAPPENS.: NG. TB3 warns about the overwriting of
	  the existing file (so far, so good). , but then
	  it fails to save the attachment, and 
	  there is no visual feedback with GUI, and TB3 proceeds
	  as if it succeeded.

    case (e) /tmp/c-dir
    	 Use /tmp/c-dir, but before press the "SAVE" button,
	 remove the directory from another terminal.
	 (  chmod a+w /tmp/c-dir
	    rm -fr /tmp/c-dir  
         )
	 Then Press "SAVE".
    	 
         EXPECTED: TB3 should fail the saving and warns the user.
	 	   Ideally, it sould then offer to let the user to
	 	   choose another directory (and name).  

	WHAT HAPPENS:	   OK

Scoreshhet
Summaries of  TB3 behavior in the above scenarios.

     case (a)  OK
     case (b)  NG
     case (c)  NG
     case (d)  NG
     case (e)  OK


We need to fix the failure to raise an error when TB3 tries to
save an attachment to a write-protected directory with LEFT-clicking.




---

additional information.

The original  Bug 429827 discussion
is now a  mixture of 
 - mozilla's download, and 
 - and thunderbird saving an attachment,
and the error cases where
 - the drive (I think it is very windows-specific) suddenly disappers, or
 - the target directory is write-protected.

So the focus of bug behavior became blurred after about 100 posts unfortunately.
Per a latest suggestion, I decided to create this new bug entry so that
this particular bug is understood better by many and the fix is approved sooner.


Observation: 
I doubt the The wisdom of Mozilla browser and Thunderbird sharing a code for one
for "downloading from web" (presumably), and the other for "saving an
attachment of an e-mail article ". They are very different operation.

Thus, I wanted to limit the discussion only to TB3's behavior
regarding the saving of attachment of an e-mail article,
when the left mouse button is clicked on the attachment.

I say, "LEFT" button here because
even when we limit the discussion to TB only, i.e., saving attachment from
an e-mail article, the clicking of left mouse button and the right
mouse button invokes totally different code paths for saving the
attachment.  This is in the following bugzilla entry.
 
Bug 549719  - Should UNIFY/MERGE the two different code paths for saving an attachment in a message 

The error handling in the two paths are not quite the
same.  Also, the default path used when a previous saving attemp fails
obviously are different in the two code paths.

Here, I would like to limit the discussion only to TB3's saving an attachment
by LEFT-clicking.

TIA
Correction:

I meant to say
case (a)  OK
     case (b)  NG
     case (c)  NG
     case (d)  NG
     case (e)  OK
Ouch, incorrect posting. I meant to say
case (a)  OK
     case (b)  OK   (<= not NG)
     case (c)  NG
     case (d)  NG
     case (e)  OK
Component: General → Attachments
Product: Thunderbird → MailNews Core
QA Contact: general → attachments
A condition similar to case (c) also happens with Firefox on Windows when
automatically saving an attachment to a folder for which the current user
does not have write permissions. I believe it is the same failure.
Status: UNCONFIRMED → NEW
Ever confirmed: true
> Steps re-produce. 
> I write a summary of what goes wrong and how when we try to
> save an attachment to an e-mail article to a write-protected directory.

Save location choice is affected by next settings.
Tools/Options/Attachments
  [ ] Save files to xxx
      browser.download.useDownloadDir=true
  [ ] Always ask me where to save file  
      browser.download.useDownloadDir=false
And, directory choice is affected by next settings.
> browser.download.folderList
> browser.download.dir
> browser.download.downloadDir
> messenger.save.dir <= last used directory by Tb for save mail or attachmet
> mail.compose.attach.dir <= last used directory for attachment choice
Used prefs.js entries by Tb is slightly different from browser. See next documents, for related settings.
> http://mdn.beonex.com/en/Download_Manager_preferences
> http://kb.mozillazine.org/Unable_to_save_or_download_files
Please be careful for these settings in your test.

FYI.
Tb3's behavior on Win with next settings.
> browser.download.useDownloadDir=false
> browser.download.folderList=0 (default)
Folder displayed at folder picker dialog
(1) messenger.save.dir=existent => this folder
(2) messenger.save.dir=non-existent => MRU(Most Recently Used) directory
(3) messenger.save.dir=Read permission only directory
    => The Read permission only directory at folder picker dialog
    Try to save in it.
    => Warning of no write permission, and
       asked to save directory specified by browser.download.folderList or not.
    Document says "Desktop", but offrred Desktop\My documents in my test.
(In reply to comment #4)

Thank you, WADA-san, for find details of
default directory choices.

While I am reading the comment, I realize that
the bug I noticed was for real.

Two different paths used by TB3 to save 
attachment (one path invoked by left-button clicking, and the
other by right-button clicking) use DIFFERENT
default: the left-button uses "BROWSER" default even in TB3 (!).

See 
https://bugzilla.mozilla.org/show_bug.cgi?id=549719#c17

TIA
(In reply to comment #5)
> Two different paths used by TB3 to save attachment
> (one path invoked by left-button clicking, and the other by right-button clicking)

I could see it too on Win. My previous result was my usual "context menu/save as" case. If double click/save file, Desktop(browser.download.folderList=0) was proposed with any messenger.save.dir value. It seems the reason why I sometimes saw "Desktop" as preselected directory at folder picker dialog even though I always set browser.download.useDownloadDir=false in my ordinal testing.
(In reply to comment #6)

Thank you, Wada-san, for verifying the problem.

The more people know the problem, the higher the chance it gets fixed, I hope.
I will leave that particular problem in Bug 549719 for now.

Anyway, I am posting a preliminary patch to fix the problems initially posted to this bugzilla myself, i.e., a patch nsHelperAppDlg.js to make TB3 friendly
to the case of trying to save attachment to write-protected directory.

But this patch assumes that a previous patch (indentation patch to the file is already applied.) So I am posting it this time just for reference purposes.

Once the indentation patch is accepted, I will re-post appropriate patch (including any change I may have to make to accommodate the latest indentation changes, etc.).

TIA
A patch in the works.
Not in the final patch form.

Produced by "diff -U 8" against the newly indented nsHelperAppDlg.js
(See  Bug 559833  ) which is not yet in the official repository.

So this may not be applied to the current nsHelperAppDlg.js without at least
one manual intervention for a hunk.
 
Also, there is a code for debugging near the beginning to print the
directory attribute to javascript console. (inside #if 1, #endif)

Thus not in the final patch form yet.

But this could be helpful for those who got bitten by the bug, or
developers to verify that the patch in the works fixes the said issues.
My attempt to create the working patch to the latest cleanly indented version of nsHelperAppDlg.js has failed.

The old patch I posted worked. But lately in the last couple of weeks
I don't see it work any more.

See my posting  to mozilla.dev.tech.xpcom
http://groups.google.co.jp/group/mozilla.dev.tech.xpcom/browse_thread/thread/40fbbee39bd3d8c7

After a search for the clue, I posted a message to Bug 249143 which seems to be related to the bug now I see.

Until I find the way to call alert dialog or find the replacement, showing the
alert that the writing of attachment fails due to the write-protection of the directory may be impossible.

One alternative is to show such a dialog outside nsHelperAppDlg.js, maybe after the call to promptForSaveToFile in nsExternalHelperAppService.cpp

http://mxr.mozilla.org/comm-central/source/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp#2026

But that will require an addition of clearly defined return paramter to show that
the writing failed (and the reason of the failure).

I wonder if someone can suggest a way out.

TIA
(In reply to comment #9)
> My attempt to create the working patch to the latest cleanly indented version
> of nsHelperAppDlg.js has failed.
> 
> The old patch I posted worked. But lately in the last couple of weeks
> I don't see it work any more.
> 
  [...]

Voila. A good news.

The patch works again and it can properly
show the dialog when the saving of the attachment fails
due to the missing write permission, or when
the target directory is removed when TB3 is about to save to it.

Details: 
For the last one and half months or so, I could not even compile TB3 due to 
the XPCOM reshuffle and then a strange media `raw' related problem.

But somehow the first one is over, and I put a bandage on the second problem.
Then I could compile TB3 again.
But the problem still persists in the unmodified 3.1a1pre.

I noticed that the official nsHelperAppDlg.js had a few changes and so
I incorporated the change to my patch and tested my patch again in this
new 3.1a1pre from comm-central.

Then to my delight, I found that the patch works again!

I am uploading the patch to nsHelperAppDlg.js so that
someone who wants to test it can do so on his/her computer.
Just store the modified nsHelperAppDlg.js on your mozilla's bin/components
directory if you are using the comm-central version (I think it is called nightly?). Better still, compile your version by replacing the
nsHelperAppDlg.js with the modified version :-)

Anyway a great progress for many affected users including me.

(The right-clicking case still shows the error dialog TWICE, but
at least we get warned. Before, there was total silence even though the
saving failed.)

I found out nsHelperAppDlg.js was slightly changed in the official
Attached patch A first cut to the (obsolete) — Splinter Review
(The last statement in the main comment 10 was cut short.
"I found out nsHelperAppDlg.js was slightly changed in the official
distribution and the changes were reflected in the patch." was what I meant to write.)

The uploaded patch is for evaluation purposes-only and not meant for
the immediate inclusion due to some additional error messages, which can
be disabled by #if 0, #endif easily, though.

 - I am using my own mydump() function for dumping purposes.
   The message can be seen in Error Console. (Tools -> Error Console)
   This actually is better using dump() as in the original, but
   other developers may disagree.

 - I am printing debugging messages using mydump() inside isUsableDirectory().
   The message is very, very informative, but should be removed eventually.
   (You can see immediately, for example, what default saving directory is used.)

 - function auxpromptForSaveToFile() is a function
   Basically, does the last half of the original promptForSaveToFile function.

   The creation of this function was necessitated since the original code
   never let the user retry saving after the silent failure of saving an attachment.
   (The original code that was moved into this function is
   right now commented out by #if 0, #endif)

 - The above auxpromptForSaveToFile() is called again 
   after saving to a file failed and a dialog is shown.

 - A renaming of a variable in function validateLeafName()
   aLocalFile -> aLocalFolder.
   This is more apt as far as the use in the first part of the function is concerned.
   Later, though, it also holds the leaf function name. Hmm...


 - A few comments to clarify or pose a question explicitly about the
   nature of return value. I didn't try to fix, but exposed the potent
   problem if any.
 

 - Oh, and a sprinkling of 
   "// TODO/FIXME: empty catch-clause. VERY BAD CODING PRACTICE."
   where empty catch-clause is seen.
   This is indeed very bad. A syntax error in the lower level function etc.
   is thrown as java run time error but such empty
   clause hides the existence of such syntax error during debugging. It hurts.


- I reflected the latest changes to nsHelperAppDlg.js
  Web progress listener change.
  XPCOM registration change.

  I am not sure what make my patch work again after early June failure.
  python preprocessor change (and the subsequent affected code change(s)?)
  and other minor changes noticed during XPCOM transition?

  So I have a nagging feeling something may go wrong again.
  (But the patch worked close to 10 months or so before it stopped working.)

  So posting this crude patch early may help some of you, developers,
  to test it out. And if this stops working again, maybe those
  developers can also complain -:)
Sorry typos. 

The version numbers ought to be 3.2a1pre

> But the problem still persists in the unmodified 3.1a1pre.
                                               *****************
> 
> I noticed that the official nsHelperAppDlg.js had a few changes and so
> I incorporated the change to my patch and tested my patch again in this
> new 3.1a1pre from comm-central.
**********************
I think I'll be able to try this updated patch to see if it solves the
bug on Firefox trunk too, but not before two or three weeks, I suppose.
(In reply to comment #13)
> I think I'll be able to try this updated patch to see if it solves the
> bug on Firefox trunk too, but not before two or three weeks, I suppose.

Thank you, Paulo. 

In the meantime, what is the correct procedure to try this on trunk? (The development version I tinker with, namely comm-central seems to be what is called nightly version.) Maybe I can also try the trunk build with the patch myself. Is simply obtaining the source tar ball and patch it the way to go?
(In reply to comment #14)
> (In reply to comment #13)
> > I think I'll be able to try this updated patch to see if it solves the
> > bug on Firefox trunk too, but not before two or three weeks, I suppose.
> 
> Thank you, Paulo. 
> 
  [ ... ]

>  Is simply obtaining the source tar ball and patch it the way to go?

Paulo,

I did just that. And I found the patch to nsHelperAppDlg.js.in seems to
produce a workable nsHelperAppDlg.js 
(The first time I compiled the unmodified trunk tree, nsHelperAppDlg.js
is a real file in MOZ_OBJDIR/mozilla/dist/bin/components/nsHelperAppDlg.js.
After I modified nsHelperAppDlg.js.in and re-compiled, nsHelperAppDlg.js is now
a link to a file that is produced in SRCDIR/mozilla/toolkit/mozapps/downloads/nsHelperAppDlg.js. How interesting.)

I am now uploading the crude diff for evaluation.
No consistent indentation, or the use of the function you produced to
reduce duplication several months ago, etc.
But the modified version certainly produced warning when saving the attachment
failed due to permission error.

Please try.
To evaluate the effectiveness of the proposed patch (comm-central, nightly)
forthe current TRUNK version 3.1.2, I created a diff with some
debug statement, etc.
It works as far as I can tell. Please try.
I am uploading a slightly cleaned up patch candidate for review (comm-central version.)
 - Took out one "#ifdef DEBUG, #endif" section for debugging,
 - took out large a section inside "#if 0, #endif", which is moved
   in an earlier position in the file and made into a separate function.

I hope this can be reviewed soon. I wondered who should be the reviewer.
In a separate bugzilla entry, I put Shawn as the final reviewer (bug https://bugzilla.mozilla.org/show_bug.cgi?id=559833
) so I am doing the same here. Please advise this is not the case.

TIA
Assignee: nobody → ishikawa
Attachment #463354 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #470103 - Flags: review?(sdwilsh)
Comment on attachment 470103 [details] [diff] [review]
Cleaned up patch candidate for nsHelperAppDlg.js

I'll still need to look at this, but Paolo is likely to find most, if not all of the issues I'll find and I bet he has a lot more review bandwidth.
Attachment #470103 - Flags: review?(sdwilsh) → review?(paolo.02.prg)
Comment on attachment 470103 [details] [diff] [review]
Cleaned up patch candidate for nsHelperAppDlg.js

Hello Chiaki, thanks for your contribution! In the following weeks I'll be able to review it and help you to turn this into a final patch that can be checked in. I'll work on the "mozilla-central" tree for the purpose of testing and reviewing.

There is still a lot of work to do, however. Most importantly, nearly every fix needs an automated test case, that helps avoiding regressions caused by future modifications of the code.

In fact, I can't reproduce the bug on Windows since the file picker dialog doesn't allow me to save to a write-protected directory in the first place. An automated test could instead provide a "mock" implementation of the file picker that returns a "bad" path regardless of the operating system, without showing any user interface at all.

Your automated test case should probably be a "chrome" test
(https://developer.mozilla.org/en/Mozilla_automated_testing#Chrome_tests),
and it should do the following operations:

 * Create folders with appropriate permissions in a temporary directory.
 * Set the preferences to always ask where to save the files.
 * Open the dialog that asks what to do with a downloaded file.

    You can see how this test does it:
     /toolkit/mozapps/downloads/tests/chrome/test_unknownContentType_dialog_layout.xul

 * Replace the file picker implementation with a mock one, that returns the
    file path in the temporary folder.

    You can see how this test does it:
     /toolkit/content/tests/browser/browser_save_resend_postdata.js

 * Replace the message box implementation with a mock one, that actually
    checks that the prompt about bad permissions is shown.

    You can see how this test does it:
     /toolkit/mozapps/downloads/tests/chrome/test_bug_412360.xul

 * Simulate clicking the "OK" button.
 * Detect that the test is finished, and clean everything up.

I understand that doing all of this in the right way is quite a challenge!
Especially, most calls are asynchronous and every step must be implemented
inside a callback function.

To see a chrome test in action, you can use the following command line:

TEST_PATH=toolkit/mozapps/downloads/tests/chrome/test_unkownContentType_dialog_layout.xul make mochitest-chrome

You can make a copy of the file to use as a starting point for your test.

On a related subject, I was able to manually reproduce the bug when the _default_ directory for downloads is write-protected, and that case is not actually covered by your patch yet, while I think the code should be structured to handle both cases in the same function. Probably another automated test should reproduce this specific condition, unless it is clear from the code that one test covers both cases.

On the other hand, considering that this patch is going to fix an edge case, if the patch can be reduced to a nearly one-liner, the test might not be necessary, although this is a decision that should be agreed upon by the module owner.

That said, here are my comments on the patch itself. I'll try to answer to your in-line questions, let me know if you need some other clarification. For the next version, however, please make sure that the patch is in its "final" form, so that the result is how you intend it to appear when checked in.

>+ * Helper for debugging in XPCOM component.
>[...]
>+function mydump(msg)
>+{
>+  Components.utils.reportError(msg);
>+}

In fact, debugging functions should not be present in the final form.

>+///////////////////////////////////////////////////////////////////////////////
>+//// auxpromptForSaveToFile()

If I understand correctly, this displays the file picker and deletes an existing
file if the user chose to overwrite. Please name the function accordingly.

>+// @aLauncher               same as in promptForSaveToFile

For new functions, use JSDoc-style comments. Example:

http://mxr.mozilla.org/comm-central/source/mozilla/toolkit/mozapps/downloads/DownloadUtils.jsm#206

Also, provide an explicit explanation of the meaning of the parameters.

>+function  auxpromptForSaveToFile (aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, baseobject) {

Why a global function with a "baseobject" parameter? This should be a member function inside the object prototype, and continue to use "this" instead of "baseobject".

>+  baseobject.debug = true;

Debug code to be removed.

>+  // The last directory preference may not exist, which will throw.
>+  try {
>+    var lastDir = gDownloadLastDir.file;
>+    if (isUsableDirectory(lastDir))
>+      picker.displayDirectory = lastDir;
>+  }
>+  catch (ex) {
>+  } // TODO/FIXME: empty catch-clause.  VERY BAD CODING PRACTICE.

Empty catch clauses are necessary sometimes, especially when they wrap
a single statement that is expected to raise an exception in some usual
cases but we don't know exactly which exception (it's the case of the
MIME method calls, for instance).

In this case, given the comment in the code, the try-catch block may be
limited to getting "gDownloadLastDir.file". Make sure that exceptions
with isUsableDirectory are handled correctly, however.

>+  if (picker.show() == nsIFilePicker.returnCancel) {
>+    // null result means user cancelled.
>+    // TODO/FIXME: this type of overloading of meaning should
>+    // be avoided. We should have an out parameter that tells
>+    // us the user action explicitly. (cancel in this case.)
>+    return null;
>+  }

As long as this is documented, having the function return null for
an expected outcome is acceptable, even recommended to avoid the
overhead of having out parameters in JavaScript. Exceptions can
instead be used for unlikely failure cases.

>+    catch (e) {
>+      // TODO/FIXME: remove above can fail due to NS_ERROR_FILE_ACCESS_DENIED here,
>+      // or even some timing-related race conditions between the exists() check
>+      // (which returns true) and remove() operation if somebody removes
>+      // the file in-between.

Then you should check for the corresponding exception and filter it.

>+      if (e.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
>+        // TODO/FIXME
>+        // Here we want to see the save operation dialog re-displayed.
>+        // How do we achieve this?

Leave the responsibility for handling exceptions to the outer function
(as you are correctly doing already).

>+//// nsUnknownContentTypeDialog  : a typo!

Just fix it! :-)

>       let autodownload = false;
>       try {
>         autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR);
>-      } catch (e) { }
>+      } catch (e) { } // TODO/FIXME: empty catch-clause. VERY BAD CODING PRACTICE.

Example of appropriate empty catch clause. We don't know the exact result code,
and we don't want to report the error to the console.

>+            // TODO/FIXME: So what do we want to return here?
>+            // At least under linux, there doesn't seem to be an ill-effect
>+            // with "return" only.
>             return;

"return null" is better, good catch.

>+            // Display error alert (using text supplied by back-end)
>+            prompter.alert(this.dialog,
>+                           bundle.GetStringFromName("badPermissions.title"),
>+                           bundle.GetStringFromName("badPermissions"));

I've seen the same lines in other parts of the code. The code should instead
be structured to have a single instance of this call.

>+        // WE BREAK OUT OF LOOP of here.
>+        // Actually a simple "return result" will do
>+        // this is not very clear enough! So I wrote the code as below.
>+        if(result == null) // user cancelled.
>+        {
>+          return null;
>+        }
>+        else
>+        {
>+          break;
>+        }
>+      } // end while
>+      return result;

Just move "return result" in the infinite loop, and ensure that there are no break statements inside.

Also, the fact that the save dialog is re-displayed in case of early error detection is a separate change. It certainly needs a separate test, and we have to decide if this is actually the behavior we want, as in most other cases we can't detect the error so early and the dialog isn't re-displayed in any case, so the behavior might seem inconsistent from the user's point of view.
Attachment #470103 - Flags: review?(paolo.02.prg)
(In reply to comment #19)
> Your automated test case should probably be a "chrome" test
> (https://developer.mozilla.org/en/Mozilla_automated_testing#Chrome_tests),
> and it should do the following operations:
Could probably do it with xpcshell too.

> I understand that doing all of this in the right way is quite a challenge!
> Especially, most calls are asynchronous and every step must be implemented
> inside a callback function.
Note that generators can help here.  A number of these tests use this technique:
http://mxr.mozilla.org/mozilla-central/source/dom/indexedDB/test/

> On the other hand, considering that this patch is going to fix an edge case, if
> the patch can be reduced to a nearly one-liner, the test might not be
> necessary, although this is a decision that should be agreed upon by the module
> owner.
We should probably write the test so we don't regress this in the future.

> Also, the fact that the save dialog is re-displayed in case of early error
> detection is a separate change. It certainly needs a separate test, and we have
> to decide if this is actually the behavior we want, as in most other cases we
> can't detect the error so early and the dialog isn't re-displayed in any case,
> so the behavior might seem inconsistent from the user's point of view.
Probably should be done in a follow-up bug too.
(In reply to comment #19 and comment #20)

I will study the comment to generate the test case.
(I have been manually creating the temporary directory under /tmp
and set the attribute with chmod to create a write-protected directory for this
bug.)

I was surprised to learn that Windows doesn't allow one to pick a write-protected
directory for the attachment saving. (I am not sure if this were the case with
my XP SP3 environment, but a clever GUI library would certainly tries to
enforce some restraint and such behavior is understandable.)

I will also study the comments about the patch style, etc. and
come up with a better patch in the next several days hopefully.

TIA
(In reply to comment #21)
> I was surprised to learn that Windows doesn't allow one to pick a
> write-protected
> directory for the attachment saving. (I am not sure if this were the case with
> my XP SP3 environment, ...

I think the problem discussed in this thread may only occur on POSIX-compliant
systems such as linux, Solaris, FreeBSD, etc.
(And later version of windows such as Vista(?), Windows 7(?), maybe?)

XP SP3 shows strange behavior.

Under Windows, I did the following.

create a directory:   c:\download\readonly-dir

make it read-only:     attrib +r c:\download\readonly-dir

checked it using "ls -ld" from cygwin.
 
C:\Documents and Settings\ci>ls -ld /cygdrive/c/download/readonly-dir
dr-x------+ 1 ci blahblah 0 2010-09-02 10:30 /cygdrive/c/download/readonly-dir

blahblah shows something unreadable (must be a group name in Japanese characters
or something.)

Then I used TB 3.1.2 under XP SP3, and tried to save an attachment
to this read-only directory.

To my surprise, the download manager window appears for a flick of a second
indicating the write-operation (?).
To my bewilderment, the attachment was saved to the directory(!)

So either, 
- the "attrib +r" may not be the proper way to make a read-only directory
  under XP SP3,  OR
- TB 3.1.2 doesn't enforce the read-only property of a directory and write into
  it anyway (and XP allows such writing, or maybe the runtime library
  did some magic like make the directory writable and then revert it
  to read-only?).

I am a bit perplexed. But these must be very peculiar to Windows XP, I suppose.

At least, under linux, the write-protection mechanism works and
TB3 fails to write an attachment to a write-protected directory,
but the warning as to this failure is not shown.

Honestly, I won't be able to handle Window's strange behavior without
clear explanation of what is going on.

TIA
(In reply to comment #20)
> (In reply to comment #19)
> > Your automated test case should probably be a "chrome" test
> > (https://developer.mozilla.org/en/Mozilla_automated_testing#Chrome_tests),
> > and it should do the following operations:
> Could probably do it with xpcshell too.
> 
> > I understand that doing all of this in the right way is quite a challenge!
> > Especially, most calls are asynchronous and every step must be implemented
> > inside a callback function.
> Note that generators can help here.  A number of these tests use this
> technique:
> http://mxr.mozilla.org/mozilla-central/source/dom/indexedDB/test/
> 
 ...
> We should probably write the test so we don't regress this in the future.
> 

I have tried to understand the test framework, but being a JavaScript newbie doesn't help me very much.

Also, I found the explanation in various articles are very heavily tuned to
the browser debugging if I am not mistaken.

Can someone point at a good example of TB3 test case that is generated
by the generator or to be used by xpcshell?

To be frank, at this stage, writing the test in javascript for TB3 seems to be the highest barrier for any submitter of reasonably complex patch :-(

TIA

PS: Re XP's strange behavior, since my XP account has the administrative 
priviledge, maybe the C or C++ runtime didn't bother to check for
the write permission but simply wrote the file to a write-protected directory
(Emacs, a ka meadow port, probably checks the write permission bit and warns the user to show a behavior similar to POSIX environment.)
(In reply to comment #23)
> To be frank, at this stage, writing the test in javascript for TB3 seems to be
> the highest barrier for any submitter of reasonably complex patch :-(

It is often the toughest and most time consuming part indeed, but once you
understand how to leverage it, it makes your development workflow much easier.

Understanding the inner workings of the framework is a huge task, and I never
attempted it. The good news are that you don't need to understand it to
begin writing new tests or running existing tests. The framework is mostly
automated, and should work with only a few manual steps, that are the ones
explained in the build guide (like creating ".mozconfig" and so on).

This is in fact the approach I follow when I have to work with code bases as
complex as the testing framework. I start from scratch, following with a lot
of attention all the instructions in the documentation I can find, and run
the program (tests in this case) in the default configuration. Only at this
point I make changes and see the effect they have - sometimes I start with
a change totally unrelated to the task at hand, just to see if it has the
effect I expect, and gain confidence with the development tools.

In the case of Mozilla applications, the documentation allowed me to set up
a test environment easily, even though it required a lot of time and patience.
I started with building Firefox. The components in the Thunderbird build
system are basically a superset of the ones of Firefox, and thus building
and running tests on it is just a _bit_ more complex. Since your change is
part of Toolkit, which is a portion shared by all the Mozilla applications,
I think you can make your change in a Firefox build, if you think this may
help you in folllowing the build and test instructions.

I don't have a Thunderbird build and I can't figure out how an xpcshell test
might work for this case, maybe Shawn might help with this. In fact, the best
references I can provide at present are the ones in comment 19. In any case,
I think your first goal might be to run the "unknownContentType_dialog_layout"
mochitest, then make a change in the test to see it fail:

TEST_PATH=toolkit/mozapps/downloads/tests/chrome/test_unknownContentType_dialog_layout.xul make mochitest-chrome

This is for a Firefox build, maybe TEST_PATH is different if you have a
Thunderbird build.

Then, in order to make changes towards the final goal of testing the patch
you are writing, you should study some of the advanced language features
introduced in recent JavaScript versions, like generators and iterators:

https://developer.mozilla.org/en/JavaScript/Guide/Iterators_and_Generators

Even if you'll not be using such features, this will make you understand
the code of other tests you can use as reference. Also, you have to be
familiar with the event system of the Document Object Model, since it is
used by tests when they load web pages and drive XUL dialogs.

If you have a specific question you can't find in the documentation, just
ask! I don't have a lot of time available now, so the answer might come
after some days, but I'll do my best, within the limits of what I know.
For questions that you think have a simple answer, you may also try asking
in realtime in the #developers IRC channel.
(In reply to comment #24)
> I don't have a Thunderbird build and I can't figure out how an xpcshell test
> might work for this case, maybe Shawn might help with this. In fact, the best
> references I can provide at present are the ones in comment 19. In any case,
> I think your first goal might be to run the "unknownContentType_dialog_layout"
> mochitest, then make a change in the test to see it fail:
> 
> TEST_PATH=toolkit/mozapps/downloads/tests/chrome/test_unknownContentType_dialog_layout.xul
> make mochitest-chrome
> 
> This is for a Firefox build, maybe TEST_PATH is different if you have a
> Thunderbird build.
Given that this is a patch to toolkit functionality, the test should be developed to be ran in the browser (which is where we run tests in mozilla-central).  Thunderbird will still pick up the changes.
(In reply to comment #25)
> Given that this is a patch to toolkit functionality, the test should be
> developed to be ran in the browser (which is where we run tests in
> mozilla-central).  Thunderbird will still pick up the changes.

Thank you for the pointer. Many test documents describe the testing of Firefox and
so I will try to figure out how to create a test case that touches the situation
in the browser case.

TIA
Hi,

Since September/October last year, I could not get the compilation/linking of TB trunk succeed on my Debian GNU/Linux  due to various errors : Debian GNU/Linux toolchain issues, and some shuffle due to XPCOM framework changes, etc.  And thus, I could not
get to improve the patch (to address issues raised by Paulo not to mention the eventual creation of test cases for testing framework.) during that time. (I was forced to doing other things such as looking and counting the warnings generated during the failed compilation, etc.  http://bugzilla.mozilla.org/show_bug.cgi?id=609210

Lately, however, I was able to compile/link TB trunk again finally, and will try to create a new patch that hopefully addresses issued raised by Paulo.

Hmm. Creating testing in browser as noted by comment 25, "the test should be developed to be ran in the browser"
will be the biggest challenge for me fixing TB.

Also, the demise of the javascript debugger (?) mentioned below
in the add-ons page for TB 

https://addons.mozilla.org/ja/thunderbird/addon/javascript-debugger/

is a blow to me since
nsHelperAppDlg.js is after all a javascript and
already I have a problem in javascript interpreter 
seemingly raising a mysterious error which I can't fathom after I modified the patch somewhat, but have no way to figure it out yet. :-(
(The above URL is a Japanese page, please search for javascript debugger
in the search box to reach your preferred language page.)

So please don't hold your breath, but I am progressing again and hope to produce a patch (and the test) soon.

TIA

PS: The latest trunk (Shredder) seems to have changed the UI for attachment saving somewhat: Now you can't double click (LEFT clicking) the attachment directly to raise a pop-up, but rather the first clicking expands the attachment to show the name, etc. and then on it, you can click further to open the dialog for saving. 
For right-clicking, you already have a "SAVE" button in the right of the row where the attachment is shown, and you can click on the button to invoke the same functionality which was previously invoked by right-clicking on the attachment (and still is).  

So the UI changes somewhat, but the functionality remains the same, and the bug is there, too.
(Silent failure to save to a non-writable directory [via left-click], and showing of error dialog TWICE [via right-click].)
Hi, almost 9 months after the last review of my patch (later part of Comment 19), I finally 
could compile/link TB trunk (hg repository) on my Debian GNU/Linux installation again, and am uploading a new patch against the latest TB trunk
addressing the issues mentioned in comment 19.

Here is my comment on the review.
The patch will be uploaded in a few minutes.

>That said, here are my comments on the patch itself. I'll try to
>answer to your in-line questions, let me know if you need some other
>clarification. For the next version, however, please make sure that
>the patch is in its "final" form, so that the result is how you intend
>it to appear when checked in.

Below is the
numbered response and the original review comment, followed by some
additional comments of mine.


1: I left the code in the comment.

   The reason is that 
   - this file has been the source of many problems over the yeas, and
     I am sure someone wants to hack this code sooner or later again.
     I think for would-be programmer, the hint about using one's own
     debug output routine is very important. Without this, I would not
     have been able to debug this code. JavaScript debugger is not
     quite user-friendly when I tried it.

>+ * Helper for debugging in XPCOM component.
>[...]
>+function mydump(msg)
>+{
>+  Components.utils.reportError(msg);
>+}
>
>In fact, debugging functions should not be present in the final form.

2. I have changed the name to `auxDisplayFilePickerForSaveToFile()'

>+///////////////////////////////////////////////////////////////////////////////
>+//// auxpromptForSaveToFile()

If I understand correctly, this displays the file picker and deletes an existing
file if the user chose to overwrite. Please name the function accordingly.

3. I used the JSdoc-style comments for new functions. 

DONE : 
>+// @aLauncher               same as in promptForSaveToFile
>
>For new functions, use JSDoc-style comments. Example:
>
>http://mxr.mozilla.org/comm-central/source/mozilla/toolkit/mozapps/downloads/DownloadUtils.jsm#206

>
>Also, provide an explicit explanation of the meaning of the parameters.
>
   Provided the type and meaning for a few of them. 

   However, for a few parameters to original promotForFileToSave, I
   have not been able to figure out exactly what they are supposed to
   be. I never bothered.


4: Fixed.
>+function  auxpromptForSaveToFile (aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, baseobject) {
>

>Why a global function with a "baseobject" parameter? This should be a
> member function inside the object prototype, and continue to use
> "this" instead of "baseobject".

Indeed. So I changed this into proper member functions, and 
use `this' instead of passing it as a parameter.

I was under a mistaken impression that an unexported (or hidden)
member function in a class that is accessed via XPCOM mechanism ought
to be declared (as hidden) in the corresponding *.idl file even if
this function is hidden (and not exported.). So I thought to move this
function as a global because I didn't want to touch *.idl file.

Of course, I was wrong(!).

And so the functions are now proper member functions and base is used
there. (It seemed the last time I tried to use member function a
couple of years ago, when I experimented with tinkering this file, it
didn't work because I put the function into the wrong class that
appeared in this file earlier than the correct one by mistake:

E.g.: BAD  nsUnkownContentTypeDialogProgressListener.prototype = ...
      GOOD nsUnknownContentTypeDialog.prototype = ...

This time, I made the same mistake again, and figured out the problem
by accident.  Hmm... I need a better pair of glasses, or need to set
larger font for Emacs session, I suppose.

(By the way the first prototype name seems to be misspelled, but
I am afraid that it must stay as is since it seems it is exported and
used in other files(?).)


5.

>+  baseobject.debug = true;
>Debug code to be removed.

Again, I left it as a comment so that future would-be hacker find it
easier to start working on this file.


6. Empty clauses.

>+  // The last directory preference may not exist, which will throw.
>+  try {
>+    var lastDir = gDownloadLastDir.file;
>+    if (isUsableDirectory(lastDir))
>+      picker.displayDirectory = lastDir;
>+  }
>+  catch (ex) {
>+  } // TODO/FIXME: empty catch-clause.  VERY BAD CODING PRACTICE.

>Empty catch clauses are necessary sometimes, especially when they wrap
>a single statement that is expected to raise an exception in some usual
>cases but we don't know exactly which exception (it's the case of the
>MIME method calls, for instance).
>
>In this case, given the comment in the code, the try-catch block may be
>limited to getting "gDownloadLastDir.file". Make sure that exceptions
>with isUsableDirectory are handled correctly, however.

The points are well taken.

However, the rampant use is not limited to legitimate cases, and as I
noted earlier, this type of wholesale catching of errors interfered
with catching the legitimate errors of coding (such as syntax errors
noticed by the interpreter) in some cases.  So I still mark some
places as "{E|e}mpty catch-clause" to alert the future would-be
hackers.

Please understand that I *mark* them for future would-be hackers as a
possible trouble spot in the long run.

7. I tried to document the return type of a few functions and
   the flow.

>>+  if (picker.show() == nsIFilePicker.returnCancel) {
>>+    // null result means user cancelled.
>>+    // TODO/FIXME: this type of overloading of meaning should
>>+    // be avoided. We should have an out parameter that tells
>>+    // us the user action explicitly. (cancel in this case.)
>>+    return null;
>>+  }
>

>As long as this is documented, having the function return null for an
>expected outcome is acceptable, even recommended to avoid the
>overhead of having out parameters in JavaScript. Exceptions can
>instead be used for unlikely failure cases.


8.

>>+    catch (e) {
>>+      // TODO/FIXME: remove above can fail due to NS_ERROR_FILE_ACCESS_DENIED here,
>>+      // or even some timing-related race conditions between the exists() check
>>+      // (which returns true) and remove() operation if somebody removes
>>+      // the file in-between.

>Then you should check for the corresponding exception and filter it.

For this, I tried to check the error(s) returned when a file already
exists and is not writable, and the directory that holds it unwritable.
The current code handles it very well.

However, the recent GUI library, GTK 2, under Debian GNU/Linux has
become very clever since last year, and I can not test unusual
cases any more.
E.g.
FilePicker under Gnome? is much wiser.
It seems that it checks internally whether the pathname up to the last file
component exists or not (for example, non-existing directory is checked!).

So previously, last year, I could create /tmp/b-dir, then trying to
save the attachment there, and seeing the file picker start for saving
the attachment and choose /tmp/b-dir, and then before hitting SAVE, I
could remove /tmp/b-dir and then hitting SAVE and see the action of
TB3 to handle the missing directory.
(/tmp/b-dir/saved-attachment-file-name is passed back to TB3 but
/tmp/b-dir/ is no longer existing, and thus should fail.)

But now, I think before returning the /tmp/b-dir/saved-attachment-file-name
to TB3, file picker on its own checks that /tmp/b-dir/ exists and
if b-dir doesn't exist any more, hitting SAVE is a basically a noop, but
it changes the location to save the file, and we are now
moved to immediately below /tmp to continue specifying where to save the
attachment.

A good improvement in the external GUI library.
 
>>+      if (e.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
>>+        // TODO/FIXME
>>+        // Here we want to see the save operation dialog re-displayed.
>+        // How do we achieve this?
>
>Leave the responsibility for handling exceptions to the outer function
>(as you are correctly doing already).

Noted and commented as such.

9.

//>+//// nsUnknownContentTypeDialog  : a typo!
//
//Just fix it! :-)

Fixed.

10:
>>       let autodownload = false;
>>       try {
>>         autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR);
>>-      } catch (e) { }
>>+      } catch (e) { } // TODO/FIXME: empty catch-clause. VERY BAD CODING PRACTICE.
>
>Example of appropriate empty catch clause. We don't know the exact result code,
>and we don't want to report the error to the console.

OK.

11.

//>+            // TODO/FIXME: So what do we want to return here?
//>+            // At least under linux, there doesn't seem to be an ill-effect
//>+            // with "return" only.
//>             return;
//
//"return null" is better, good catch.

now, return null.

12.

>>+            // Display error alert (using text supplied by back-end)
>>+            prompter.alert(this.dialog,
>>+                           bundle.GetStringFromName("badPermissions.title"),
>>+                           bundle.GetStringFromName("badPermissions"));
>
>I've seen the same lines in other parts of the code. The code should instead
>be structured to have a single instance of this call.

Done. See   displayBadPermissionAlert()


13.
//>+        // WE BREAK OUT OF LOOP of here.
//>+        // Actually a simple "return result" will do
//>+        // this is not very clear enough! So I wrote the code as below.
//>+        if(result == null) // user cancelled.
//>+        {
//>+          return null;
//>+        }
//>+        else
//>+        {
//>+          break;
//>+        }
//>+      } // end while
//>+      return result;
//
//Just move "return result" in the infinite loop, and ensure that there are no break statements inside.

done.


14. I am not sure.

NOT SURE/TODO/FIXME

>Also, the fact that the save dialog is re-displayed in case of early
>error detection is a separate change. It certainly needs a separate
>test, and we have to decide if this is actually the behavior we want,
>as in most other cases we can't detect the error so early and the
>dialog isn't re-displayed in any case, so the behavior might seem
>inconsistent from the user's point of view.

As I noted above, the better FileChooser offered by GUI library makes
it difficult for applications to pick up a file pathname with
non-existiing intermediate directory name and such, and so we have
less chance of getting into trouble for better or worse.  (And as a
matter of fact, creating such situation for testing is difficult now.)

15. In one place I added try/catch because when I cancel the
file picker, that code raises an error that is not caught by any
outside routine and recorded in the Error console.
(This may have never been a problem before in the old code?)


TIA

PS: Now on to the test script if the patch looks OK.
The new patch against Trunk (!)
Attachment #470103 - Attachment is obsolete: true
Attachment #537791 - Flags: review?(paolo.mozmail)
Comment on attachment 537791 [details] [diff] [review]
Proposed patch to nsHelperAppDlg.js  (Trunk)

(In reply to comment #28)
> Hi, almost 9 months after the last review of my patch (later part of Comment
> 19), I finally 
> could compile/link TB trunk (hg repository) on my Debian GNU/Linux
> installation again, and am uploading a new patch against the latest TB trunk
> addressing the issues mentioned in comment 19.

Welcome back, Chiaki! And thank you for your renewed interest in improving
Thunderbird and Firefox, even for users with less common configurations.
I'll try and follow this patch closely, though I've a lot of other work
to do in these days, thus reviews and comments on my part might require
some more time than usual.

Given that there's still a lot of work to do to reach the final form of
the patch, including writing the automated test cases, I recommend you
use a few common strategies that facilitate review, thus improving the
time to completion.

Most importantly, the current patch contains the changes required to fix
this bug, plus other changes related to showing the file picker multiple
times in case of errors. The latter modifications should really be handled
in a separate patch and bug, firstly to facilitate review, and secondly
because there will be discussions to understand if this is what we want
or not, which might require input from User Experience people (ui-review).

Secondly, the size of the patch should be kept to the shortest possible.
Sometimes, review iterations that go in the right direction will see the
patched file becoming shorter which each review (for example, because
common code is shared in a single function). We also keep discussions
as meta-data, in the bug, and only leave TODO comments in the code if
there is an open task that's likely to result in a specific action (with
an associated bug number). We can do this because anyone can find the bug
associated with a change using the Mercurial version control interfaces,
thus finding out the reasoning behind some of the choices made in the code.

Finally, with regard to debugging aids and references to best practices left
in the code, they're mostly unnecessary. Working on an in-house project and
working on one with thousands of active developers is very different. Consider
for example that the Mozilla development community is diverse, and not
everyone uses the same tools and techniques for debugging. I sometimes used Chromebug as my debugger, and in that case dump functions served no purpose
for me. In other cases I added ad-hoc reportError calls. Recommendations on
how to debug or best coding practices should be explained in the Mozilla
Developer Center documentation, where they can be found regardless of the
area of the code one's working on.

In the light of that, I'm quite confident that fixing this specific bug
(no error message in the explained cases) only requires a few lines of
modifications. Of course, feel free to raise any other issues you find with
the code as separate comments, or file other bugs.

Most of the time, actually, will be required to write the test case for the
change, as explained in comment 19. It's quite usual for a test case to be
up to ten times more complex than the change it is going to test. I'm
available if you have any question during the process.

A few more specific comments follow - other changes not noted here or covered
by the above general principles are fine!

> nsUnkownContentTypeDialogProgressListener.prototype = ...
> 
> (By the way the first prototype name seems to be misspelled, but
> I am afraid that it must stay as is since it seems it is exported and
> used in other files(?).)

Used where?

http://mxr.mozilla.org/comm-central/search?string=nsUnkownContentTypeDialogProgressListener

It doesn't seem to be exported, we can probably rename it.

> 6. Empty clauses.
> Please understand that I *mark* them for future would-be hackers as a
> possible trouble spot in the long run.

Not necessary, especially because as I said they are legitimate in some
cases. If you want to investigate and fix the unnecessary ones yourself,
by restricting the clauses to specific error codes, feel free to file a
separate bug. But it's unlikely that just marking them in the code would
result in an action, also given the effort to reward ratio (there's the
risk of breaking correct behavior for no practical gain). For new code,
the reviewers ensure that best practices are followed - no risk of
copy-and-paste code reaching the main repository, even if not marked :-)

> As I noted above, the better FileChooser offered by GUI library makes
> it difficult for applications to pick up a file pathname with
> non-existiing intermediate directory name and such, and so we have
> less chance of getting into trouble for better or worse.  (And as a
> matter of fact, creating such situation for testing is difficult now.)

Automated test cases won't use the file picker, so you should be able to
emulate the behavior (which might still happen on other platforms). More
generally, I think now it's up to you to judge if fixing this bug is still
relevant for Thunderbird users, given the evolution of the hosting platforms.

> 15. In one place I added try/catch because when I cancel the
> file picker, that code raises an error that is not caught by any
> outside routine and recorded in the Error console.
> (This may have never been a problem before in the old code?)

We should check that eating the error is not affecting other callers or code
paths, which might assume that the error is propagated. So this small change
might also be worth of being handled in a separate bug.
Attachment #537791 - Flags: review?(paolo.mozmail)
(In reply to comment #30)
...

> Welcome back, Chiaki! And thank you for your renewed interest in improving
> Thunderbird and Firefox, even for users with less common configurations.
> I'll try and follow this patch closely, though I've a lot of other work
> to do in these days, thus reviews and comments on my part might require
> some more time than usual.
> 
> Given that there's still a lot of work to do to reach the final form of
> the patch, including writing the automated test cases, I recommend you
> use a few common strategies that facilitate review, thus improving the
> time to completion.
> 
> Most importantly, the current patch contains the changes required to fix
> this bug, plus other changes related to showing the file picker multiple
> times in case of errors. The latter modifications should really be handled
> in a separate patch and bug, firstly to facilitate review, and secondly
> because there will be discussions to understand if this is what we want
> or not, which might require input from User Experience people (ui-review).

Thank you for Paulo for quick run down on the problems of the current patch.

I will address the issues and produce a minimal patch, and possibly filing a separate bug entry to shorten the patch.

I should be able to do this over the weekend or until next Tuesday.

TIA.
I filed a separate bug,

Bug 663667 - TB throws an uncaught error when user cancels file picker during saving of mail attachment (left-clicking)

to take care of the following.

>> 15. In one place I added try/catch because when I cancel the
>> file picker, that code raises an error that is not caught by any
>> outside routine and recorded in the Error console.
>> (This may have never been a problem before in the old code?)

>We should check that eating the error is not affecting other callers or code
>paths, which might assume that the error is propagated. So this small change
>might also be worth of being handled in a separate bug.>

The uncaught error is generated with the original pristine nsHelperAppDlg.js
from trunk distribution.

Separating this bug will shorten my next proposed patch.
I am uploading a patch that contains only the
 - spelling fixes
 - proper js doc description, and
 - in one place, change aLocalFile => aLocalFolder changes.

I am hoping that this patch is short and less controversial than the previous one so that
it can be applied in advance for the
main patch to fix the problem.

Any comment?
This is a short patch to solve minor spelling, comment, and a issue concerning the appropriateness of an ID.
It is hoped that this patch is applied before the main patch to fix the problem so that the final patch would be shorter and easier to review.
Attachment #537791 - Attachment is obsolete: true
Attachment #538754 - Flags: review?(paolo.mozmail)
Comment on attachment 538754 [details] [diff] [review]
[checked in] Spelling fix, proper JS documentation fix, one ID change.

Excellent! :-) Looks good to me. I suppose you tested the affected code paths
and everything worked fine?

The Downloads module owner should also review the patch before check-in, but
since these are just spelling fixes I don't expect it will take too long.
I've already set the additional review flag.
Attachment #538754 - Flags: review?(sdwilsh)
Attachment #538754 - Flags: review?(paolo.mozmail)
Attachment #538754 - Flags: review+
Moving to the toolkit product, as the actual issue here is in the toolkit code.
Component: Attachments → Download Manager
Product: MailNews Core → Toolkit
QA Contact: attachments → download.manager
(In reply to comment #35)
> Comment on attachment 538754 [details] [diff] [review] [review]
> Spelling fix, proper JS documentation fix, one ID change.
> 
> Excellent! :-) Looks good to me. I suppose you tested the affected code paths
> and everything worked fine?
> 

Yes, I did. Saving to writable directory, and [failed] writing to non-writable directory [which fails silently], etc.


> The Downloads module owner should also review the patch before check-in, but
> since these are just spelling fixes I don't expect it will take too long.
> I've already set the additional review flag.

Thank you!
Ping?

Has the patch mentioned above in comment #34 been reviewed by
the toolkit module owner?
I wish that it is included in the comm-central repository (and the mozilla subdirectory below it), so that the
major patch for the fix can now be uploaded with less cluttering.

TIA
Comment on attachment 538754 [details] [diff] [review]
[checked in] Spelling fix, proper JS documentation fix, one ID change.

r=sdwilsh
Attachment #538754 - Flags: review?(sdwilsh) → review+
(In reply to Shawn Wilsher :sdwilsh from comment #39)
> Comment on attachment 538754 [details] [diff] [review]
> Spelling fix, proper JS documentation fix, one ID change.
> 
> r=sdwilsh

Thank you! I am keeping my fingers crossed.
While waiting for the previous patch to fix spelling errors, and others,
here is the current WHOLE patch in the works.

The reason I am posting is that I have finally covered all the major error cases that are visible to the users using a generic I/O error message function.
(You can check what is going on by looking at post that was sent to the
mozilla.dev.platform newsgroup on Oct 26, 2011 and some follow-ups.)
In a nutshell, nsIErrorService which should give us a hook to look for
error message strings for typical error code returned by XPCOM routines, etc.
doesn't work today very well.
So I had to create a function to map an error code to short English message.
This will do for now.

It can now handle the case of disappearing directory
(e.g., trying to save to /tmp/c-dir/attachment, and suddenly /tmp/c-dir
disappears since it is deleted by another process),
and writing to a CDROM device [which returns a very strange error 
indeed.]

I thought some users waiting for the final fix to land may want to see how the
current final patch looks like.

I intend to remove the debug output from the current patch and re-submit.
But this will have to wait for the previous lighter patch to land 
to fix the minor spelling issues, etc.
This is a screen capture after an error dialog appears when
trying to save to /tmp/c-dir/attachment from the file picker, but
before the real writing takes place, the directory was removed
from another terminal.
You can see the debug output in the error console (thanks to mydump() function
in the patch) and figure out how the execution proceed in the proposed patch.
How general is this patch? The bug was moved into Download manager. Is it possible this will help also with bug 700114 in Firefox?

Can any of your older patches be marked obsolete (superseded by newer ones)? There are currently 5 active attachments and 3 obsolete ones.
(In reply to :aceman from comment #43)
> How general is this patch? The bug was moved into Download manager. Is it
> possible this will help also with bug 700114 in Firefox?
> 

I think this will solve the case when download manager 
gives the user the false impression that the saving occured
while there was an error underneath and nothing happens.

I will post a comment there.
The earlier check before the saving doesn't happen
on linux because I think iswritable() and isreadable()
implementations are bogus on linux.

> Can any of your older patches be marked obsolete (superseded by newer ones)?
> There are currently 5 active attachments and 3 obsolete ones.

I will try to see what I can.

I am waiting for the spelling fix to land first so that the
final patch is much easier to evaluate by people in the know.
But the spelling patch has somehow took much longer than usual to land :-(
OK, if you can't land the first patch yourself I have added the "checkin-needed" keyword so that people with permissions will find it and land it for you into comm-central. It seems it has proper reviews.

Also, the platform is set to Win XP, but I have the impression you talk about linux in the comments. What platform does the bug and fix apply to?
Keywords: checkin-needed
Version: unspecified → Trunk
> Also, the platform is set to Win XP, but I have the impression you talk
> about linux in the comments. What platform does the bug and fix apply to?

Thank you.

The problem was noticed under linux, but the fix should be applicable to all other platforms.
I'll set the link to bug 700114 so that it doesn't get missed. If your final patch gets approved I'll check if it helped in any way in Firefox.
Blocks: 700114
OS: Windows XP → All
Hardware: x86 → All
Also, after you clean up (mark obsolete) the patches here, can you request review for your current patch?
(In reply to :aceman from comment #48)
> Also, after you clean up (mark obsolete) the patches here, can you request
> review for your current patch?

Will do. I hope to finish it very soon.
Whiteboard: [checkin-needed for c-c]
Attachment #447525 - Attachment is obsolete: true
Attachment #464120 - Attachment is obsolete: true
I have tried to mark the patches for you. I hope I got it right.
I understand it only the "Spelling fix" patch should be landed right now. And then you will update the rest of the patch and get the reviews.
Whiteboard: [checkin-needed for c-c] → [checkin-needed for c-c, only patch 538754]
(In reply to :aceman from comment #50)
> I have tried to mark the patches for you. I hope I got it right.
> I understand it only the "Spelling fix" patch should be landed right now.
> And then you will update the rest of the patch and get the reviews.

That is correct. Thank you very much.
TIA
Keywords: checkin-needed
Whiteboard: [checkin-needed for c-c, only patch 538754] → [inbound, but leave open]
Comment on attachment 538754 [details] [diff] [review]
[checked in] Spelling fix, proper JS documentation fix, one ID change.

Landed on inbound, should be merged to central soon:

https://hg.mozilla.org/integration/mozilla-inbound/rev/031a6b22d380
Attachment #538754 - Attachment description: Spelling fix, proper JS documentation fix, one ID change. → [checked in] Spelling fix, proper JS documentation fix, one ID change.
ISHIKAWA chiaki, it seems your first patch was checked into mozilla. You can now update your source tree and update your main patch.
Will do! TIA.
This fix includes the change to properly show the error message, I/O error message support function, a few fixes for typos, etc.
I noticed that surrounding a problematic code around line 287 (line 583 in
new code) causes too much diff output and confusing.
Maybe I should have staged patches now.
One that shows only the enclosing of "try { ... } catch (e) { }"
 - this will produce only a few lines and a lot of lines with only
   whitespace changes (indentation changes due to the nesting.)

Then I can submit the whole new changes.

Thought?
Comment on attachment 593323 [details] [diff] [review]
Fix the failure to show the error message after a failure. (1st version: request for comment)

For requests for comment you can use the "feedback?" flag on the attachment. I have added it for you.
Attachment #593323 - Flags: feedback?(sdwilsh)
I am afraid that the patch was a little screwed up.
(Diff was created to a locally modified hg archive instead of
the true comm-central version, and so a few lines were
not in sync with the current comm-central and thus the diff interface from the web was difficult to read.)

I am trying to re-create the patch right now.
Clean up version (Rev 01: request for comment.)
Attachment #593323 - Attachment is obsolete: true
Attachment #593323 - Flags: feedback?(sdwilsh)
I am uploading a patch from a divided patch set.
This is to make the changes more understandable.
The following is a first patch that
only adds the top-level helper functions, and
add a try/catch clause so that
the main processing is only indented by "try { ".

The future second patch shows the remaining main change
on top of this. This should make reading the diff /comparison much easier to understand.

I wonder if such two stage patch is acceptable or not.
Comment on attachment 593720 [details] [diff] [review]
Adding top-level helper function, surround the main portion to be changed by try/catch for indention change.

It is too bad  that web diff tool doesn't show 
the difference neatly :=(, but if you apply the patch, you will see that
adding try{} only re-indented the portion (which is to be modified in the second part of the split patch)
Here, diff -cibw was performed on the nsHelperAppDlg.js after the first patch set of the split patch set.
This shows clearly that the main portion of promptForSaveToFile
is only re-indented and a pure addition of catch() is also done.
Comment on attachment 593720 [details] [diff] [review]
Adding top-level helper function, surround the main portion to be changed by try/catch for indention change.

Review of attachment 593720 [details] [diff] [review]:
-----------------------------------------------------------------

Sorry this has taken me so long to look at.  Gavin should probably be the one giving you feedback at this point.

::: toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ +133,5 @@
> +//
> +// #define NS_ERROR_GET_CODE(err)     ((err) & 0xffff)
> +// #define NS_ERROR_GET_MODULE(err)   (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff))
> +// #define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1)
> +//

This long comment isn't needed for the actual checkin.  The commit will reference the bug which will have all the background information in it :)

@@ +208,5 @@
> +    msg = "unknown error = " + code ; 
> +    break;
> +  }
> +  return "I/O error: " + msg;
> +}

gavin may have a better idea here
Attachment #593720 - Flags: feedback?(sdwilsh) → feedback?(gavin.sharp)
(In reply to Shawn Wilsher :sdwilsh from comment #65)
> Comment on attachment 593720 [details] [diff] [review]
> Adding top-level helper function, surround the main portion to be changed by
> try/catch for indention change.
> 
> Review of attachment 593720 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> Sorry this has taken me so long to look at.  Gavin should probably be the
> one giving you feedback at this point.
> 

Thank you for talking a look in your busy schedule.

> ::: toolkit/mozapps/downloads/nsHelperAppDlg.js
> @@ +133,5 @@
> > +//
> > +// #define NS_ERROR_GET_CODE(err)     ((err) & 0xffff)
> > +// #define NS_ERROR_GET_MODULE(err)   (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff))
> > +// #define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1)
> > +//
> 
> This long comment isn't needed for the actual checkin.  The commit will
> reference the bug which will have all the background information in it :)
> 


I will clean this up to reduce the clutter.

> @@ +208,5 @@
> > +    msg = "unknown error = " + code ; 
> > +    break;
> > +  }
> > +  return "I/O error: " + msg;
> > +}
> 
> gavin may have a better idea here

I will await the comment.

The patch above is the 1st stage.

After the 1st patch goes in, I will add another patch that
shows the processing the in the body of the major function 
to which some more changes are necessary.
(I split the patch into two for easier comparison.)

Combined majo patch is in the above uploadr: https://bugzilla.mozilla.org/attachment.cgi?id=593713

But anyway, I will wait for the comment for the error message function as noted above.

TIA
Attached patch 1st patch slightly cleaned up. (obsolete) — Splinter Review
The comment mentioned as frivolous was taken out.
Followed by another patch (2-patch) as the second stage: it turns out there are
so many additions in the 2-patch. So dividing the patch may not have been that
useful :-(
Second stage patch adds a few more helper function within the class (error message output for a few known cases), and many error-related processing.
I uploaded the 1st stage and 2nd stage patch after downloading the latest nsHelperAppDlg.js from comm-central and compare it against my local copy. 
Hope this helps.

TIA
Hello Chiaki-san, I'm sorry I haven't been able to provide feedback on this yet.

Can you perhaps re-summarize the current state of things, and clean up the attachments list by marking the now-obsolete patches as "obsolete", and then request review on the latest patch? I will try to get you some feedback (either from myself or someone else).
Attachment #593720 - Flags: feedback?(gavin.sharp)
It looks like only the newest patches (attachment 601242 [details] [diff] [review] and attachment 601243 [details] [diff] [review]) should be valid for review. I am not sure about attachment 593720 [details] [diff] [review]. Ischikawa, can you look at it and mark old patches as obsolete (in the Details link of each attachment).
Attachment #593720 - Attachment is obsolete: true
(In reply to :aceman from comment #71)
> It looks like only the newest patches (attachment 601242 [details] [diff] [review]
> [review] and attachment 601243 [details] [diff] [review]) should be valid
> for review. 

Thank you for the review.
The above is correct!

>I am not sure about attachment 593720 [details] [diff] [review].
> Ischikawa, can you look at it and mark old patches as obsolete (in the
> Details link of each attachment).
593720 is just to show the manual diff output and is not necessary. (The usually useful bugzilla diff output is 
a little confusing 
thus I created the manual output just to show the difference in
a neat manner.)

So I am obsoleting the old attachment(s).
Attachment #573149 - Attachment is obsolete: true
Attachment #593713 - Attachment is obsolete: true
Attachment #593721 - Attachment is obsolete: true
I obsoleted three previous patches.
Bugzilla interface was not very clear how to make an attachment obsolete (I remember seeing the reference to "obsolete" only when I posted an attachment and was asked to make previous attachments obsolete, and I am afraid that I could have done the changes in one go instead of obsoleting one attachment at a time. Sorry for the noise :-(
I think you did it right now, there was no other choice currently.

Yes, when adding a new attachment you can obsolete many older ones in one go.
Comment on attachment 601242 [details] [diff] [review]
1st patch slightly cleaned up.

This is the first patch in the two staged patches (split in two for easier
understanding.)

Helper functions for better error output, and the change in the 
flow especially for addition of try{} catch {}.

The second patch will add the details to the catch clause.
Attachment #601242 - Flags: feedback?(gavin.sharp)
Comment on attachment 601243 [details] [diff] [review]
2nd patch that follows the 1st stage patch.

A few more top-level addition of helper functions and
the details of additional error handling in catch{} clause.

TIA.
Attachment #601243 - Flags: feedback?(gavin.sharp)
OK, the problem is still there with 15.0.1 under linux.
(I have no idea why not many people complain who use TB under Windows. It seems that, unless the file system is on a remote CIFS or Samba sever with strict ACL setting, this problem may not show up under windows. Many users probably have administrative privilege like me on a local PC.)

Any chance of seeing this land in the comm-central tree before the next release?

TIA
Well, gavin sharp has not made the review of the patch. Any way to nag him about it?
Will try, but not sure how to do it :=)
You can send him a personal email:)
Or add a new reviewer for Toolkit from here:
https://bugzilla.mozilla.org/show_bug.cgi?id=567585
(In reply to :aceman from comment #80)
Sent an e-mail, and will wait for his response. If he seems too busy, then I will go for option B.
TIA
FF users, please try the following procedure to experience this bug.

In your preference, mark "Always ask me where to save files" 
and try downloading an archive from sourceforge.org.
When asked, specify a write-protected directory and see
that the saving silently fails.

---

There was a question about how this problem noticed in Thunderbird
could be reproduced in FireFox.

I answered that it would be easily reproducible ASSUMING that
Firefox DOES USE this function defined in nsHelperAppDlg.js.

I tinkered with the binary download of FF for a while.
But it was not quite clear where nsHelperAppDlg.js is invoked in FF.
(I simply tried the obvious "Save Page as", but it did not seem to
invoke the routine(s) in nsHelperAppDlg.js).

This weekend, I downloaded FF source tree from
mozilla-central, and checked by compiling FF under linux.  And
tinkered with nsHelperAppDlg.js and tried to see where it is invoked.

Now, my tentative conclusion.

Firefox no longer uses nsHelperAppDlg.js for (the most often used ?)
"Save Page as" operation: For that it seems to use routines in
nsWebBrowserPersist.{h,cpp}.

Firefox DOES USE nsHelperAppDlg.js when Firefox downloads a page,
say, an archive from sourceforge.org, and your preference for
download location is "Always ask me where to save files" before
downloading begins, THEN nsHelperAppDlg.js IS INVOKED and the failure
reported here is observed in FF, too.

Complication / black magic  under the hood

If I specify write-protected directory, say, /tmp/d-dir as the
default save location AND unmark "Always ask me where to save files",
then what happens? 
Do I get a error message?
No I do not. 

Instead, when the real download begins the offered directory to save
is automagically reverted to my default Download directory under my
home directory. Presumably unless users tinkered with it, usually
built-in default directory is write-enabled, 
and so writing will succeed! 

FF checks for the writability of the directory specified by the user,
and if it is not writable, reset the specified directory to the
built-in Default. There is a code to do this. I was not sure where
this would be meaningful/useful, but now I know.

My guess is that only developer-types bother to change the default
setting or mark "Always ask me where to save files", and thus not much
complaint from FF users about the bug here.
(And EVEN I have not changed this, and usually save file to a default
directory and then copy/move it to the final destination.)

And, again, under Windows, it seems that only write-protected remote
server directory is truely unwritable(?). Under Windows 7, as a user
with administrative privilege, I could not make TB to observe the
write-protected characteristics of directory (set by
attrib or chmod from cygwin). That is why again, this problem is not
voiced much from Windows users, I think.
(Maybe users without administrative privilege may experience the problem? I have not bothered to check. This problem under linux is significant enough as it is.)


If I recall correctly, the users who reported the similar experience
were corporate linux users who got bitten when they try to write to
remote servers (where the directory permission may not be what you
assume it to be always: admin may change it from time to time.)

Details:

I tested whether the saving to a write protected directory of a web
page fails in FF.

[File] -> [Save Page as], and then I chose /tmp/d-dir which is
write-protected, and voila!  I got a proper error message indicating
that the writing could not be performed and choose a different
directory or change the permission of the directory. Good

The error message seems to be this:
./dom/locales/en-US/chrome/nsWebBrowserPersist.properties:accessError=%S could not be saved, because you cannot change the contents of that folder.\n\nChange the folder properties and try again, or try saving in a different location.

---

But where does the error message come from?

Looking for nsWebBrowserPersist, I found many hits in files 
nsWebBrowserPersist.{h,cpp}.
But no mention of it in the obvious files with "Download" in it.
I have a hunch, that nsWebBrowserPersist-related files are where the
message comes from.

So looking further for accessError in mozilla-central 
using mxr.mozilla, I found a usages in 
/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp 

    line 1075 -- msgId.AssignLiteral("accessError");

This turns out to be a usage in the following private method
http://mxr.mozilla.org/mozilla-central/source/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
//
// nsWebBrowserPersist private methods
//*****************************************************************************
// Convert error info into proper message text and send OnStatusChange notification
// to the web progress listener.
nsresult nsWebBrowserPersist::SendErrorStatusChange( 
     bool aIsReadError, nsresult aResult, nsIRequest *aRequest, nsIURI *aURI)

So where is this SendErrorStatusChange called?

There is only one usage:
        line 143 -- nsresult SendErrorStatusChange( 

Referenced in:

    embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
        line 3712 -- SendErrorStatusChange(false, rv, nullptr, aFile); 

And, this call is in :
    embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp 
        line 3686 -- nsWebBrowserPersist::SaveDocumentWithFixup( 

Now, my tentative conclusion.

Firefox does not use nsHelperAppDlg.js for ordinary
"Save Page as" operation.

Oh, wait, the following C++ file references  "PromptForSaveToFile". Maybe this
is where the javascript version of promptForSaveToFile is invoked
through IDL interface. But I am not sure how users can invoke this
function from UI of FF.

Referenced (in 3 files total) in:

    uriloader/exthandler/nsExternalHelperAppService.cpp 
        line 1987 -- nsresult nsExternalAppHandler::PromptForSaveToFile(nsIFile ** aNewFile, const nsAFlatString &aDefaultFile, const nsAFlatString &aFileExtension)
        line 2010 -- rv = mDialog->PromptForSaveToFile(this,
        line 2097 -- rv = PromptForSaveToFile(getter_AddRefs(fileToUse), leafName, mTempFileExtension);
        line 2107 -- rv = PromptForSaveToFile(getter_AddRefs(fileToUse), mSuggestedFileName, fileExt); 

To find out where nsHelperAppDlg.js is possibly invoked, I tried
downloading a few archives from sourceforge, and found that the
automatic saving invoked by accessing a download link invokes
nsHelperAppDlg.js. And, after a few changes to preferences, basically, mark "Always ask me where to save files", I can experience the same failure to warn the
user about the failing of writing to a write-protected directory in
FF. nsHelperAppDlg.js should be fixed!

[end of memo]
Gavin, I think this patch has been waiting for your feedback since March.

ISHIKAWA, chiaki, to write private mail to Gavin, pls use gavin -#at#- gavinsharp -#dot#- com.
Flags: needinfo?(gavin.sharp)
Blocks: 30784
(In reply to Thomas D. from comment #83)
> Gavin, I think this patch has been waiting for your feedback since March.
> 
> ISHIKAWA, chiaki, to write private mail to Gavin, pls use gavin -#at#-
> gavinsharp -#dot#- com.

Just did.

Maybe we should wait until the holiday season is over.

A peaceful holiday season to everybody.

TIA
Comment on attachment 601242 [details] [diff] [review]
1st patch slightly cleaned up.

Chiaki - thank you for taking the time to prepare these patches, and for being persistent despite the delays. I'm apologize that I have not been responsive here. Generally the overall approach seems good, though the patches will need a good amount of "cleaning up" before they are ready to be committed. Here are some comments on this patch: 

>diff --git a/toolkit/mozapps/downloads/nsHelperAppDlg.js b/toolkit/mozapps/downloads/nsHelperAppDlg.js

>+// Lack of error messages for FILE I/O errors.

This comment is a little verbose :) We generally rely on much of this context being stored in bugs rather than putting it in the code. It's pretty easy to identify the bug in which a line of code was added, and so the more detailed context can just live there. Similarly, if you want to get the idea across during the review comment, you can just mention this stuff in the Bugzilla comment when attaching your patch, rather than including it in the patch.

>+// This I did after I tried to use nsIErrorService by re-defining
>+// NS_ERROR_GET_CODE() and NS_ERROR_GET_MODULE() in javascript anyway
>+// and failed.  It is attempted inside
>+// getErrMsgFromIErrorService(module_code, error_code).

As you've discovered, nsIErrorService is mostly not useful - nothing useful actually registers with the service, and there are no existing users, and so it's not really suitable for use here. We should really just remove it, since I don't think we're going to extend its use. I will file a separate bug on doing this.

>+// run grep NS_ERROR_FILE mozilla/xpcom/base/nsError.h | awk '{printf("// case  %s : msg = \"%s\" ; break; \n", substr($4, 1, length($4)-1), $2)}'
>+// to obtain the template for the following code.

These instructions seem out of date now... looks like this stuff is in xpcom/base/ErrorList.h now?

>+function myownIOErrorString(code) {

This helper function seems useful, and would be good to put in a JS module. Maybe in FileUtils.jsm.

>+function getErrMsgFromIErrorService(module_code, error_code)

As mentioned, I think you should just remove this from the patch.

>+function mydump(msg)

As Paolo mentioned a while ago, this should also be removed.

>+    // We enclose the processing to catch (previously uncaught) errors.

I think we need to be careful to only wrap the sections that would potentially throw the errors we're concerned about in the try/catch. The existing patch just puts a whole big block of code in the try/catch, and that can be confusing.

>+    catch (ex)  {  // Coping with I/O errors: We had an error exception.
>+                   // Show an error message.

This code should probably be simplified to just be:

let errorMsg = FileUtils.getMessageFromResult(ex.result);
this.displayError(errorMsg);

or somesuch.
Attachment #601242 - Flags: feedback?(gavin.sharp) → feedback+
Flags: needinfo?(gavin.sharp)
Whiteboard: [inbound, but leave open]
Comment on attachment 601243 [details] [diff] [review]
2nd patch that follows the 1st stage patch.

>diff --git a/toolkit/mozapps/downloads/nsHelperAppDlg.js b/toolkit/mozapps/downloads/nsHelperAppDlg.js

Similarly, I think this patch will need a lot of the "meta" comments removed to be landable. It probably also makes sense to combine the two patches at this point, since they're pretty closely intertwined.

>+  displayOtherErrorAlert: function(msg) {

>+    prompter.alert(this.dialog,
>+                   "I/O Error (saving a file or an attachment)", // Shown in window frame/pane
>+                   msg);

This will need to be a localized string, similar to how displayBadPermissionAlert does it.

>         // Do not store the last save directory as a pref inside the private browsing mode
>+        // (This condition is checked  inside gDownloadLastDir.setFile.)
>         gDownloadLastDir.setFile(aLauncher.source, newDir);

This comment should probably just be removed.

One thing that might also be useful is to focus on simplifying the patch, where possible. We don't necessarily need to be exhaustive about detailing the specific reasons for the failures in all cases, as long as we have suitable default behavior for handling "generic" failures. Depending on how likely these cases are hit in practice, it may be better to take a simpler approach.

Let me know if you have any questions about how to proceed, given these comments.
Attachment #601243 - Flags: feedback?(gavin.sharp) → feedback+
Dear Gavin,

Thank you for taking a look at these patches.

The patches have accumulated these "meta" comments over the months while I was
investigating the code (not only in this patch), but other issues such as
nsIErrorService (at one point it was suggested that maybe I could use it to
obtain meaningful error messages, but turned out be useless as is today, etc.).

Yes, if the general consensus seems to favor ditching nsIErrorService, I am more than happy to do it :-)

I will work on the cleaning up of the patch in the next few weeks.
I believe the general logic of the patch itself is OK since I have been using the locally modified version for quite some time now.

TIA
Great that we finally have some life here ;)
It is interesting how much code this fix needs.
Thanks for working on this Chiaki. When you have a merged/cleaned up patch I can test it on Linux too.
Keywords: dataloss
Severity: major → critical
Attached patch A work-in-progress patch (obsolete) — Splinter Review
I am obsoleting the previous two stage patches, and produced a simpler patch today.

It is still work in progress and I have not been
able to include all the suggested changes yet.

But I have created the patch against the
comm-central's latest (only a few days old) mozilla subdirectory original.
(This has been tested manually and by running "make mozmill" of TB).

We can base the discussion in the future on this patch.

TIA
Attachment #601242 - Attachment is obsolete: true
Attachment #601243 - Attachment is obsolete: true
Attachment #702397 - Flags: review?(gavin.sharp)
Slightly improved patch.
Attachment #702397 - Attachment is obsolete: true
Attachment #702397 - Flags: review?(gavin.sharp)
Attachment #705863 - Flags: review?(gavin.sharp)
>Created attachment 705863 [details] [diff] [review] [diff] [review]
>A work-in-progress patch (slightly improved)

My explanation.

The new modeline with "javascript". --- I could not get it to work as expected, so during the editing reverted to the old C++ mode line. That is not correct, but it works... I will revert it in the end when other parts of the patch are cleaned up.

First comments to Comment 85 :

>>+// Lack of error messages for FILE I/O errors.
>
>This comment is a little verbose :) We generally rely on much of this context >being stored in bugs rather than putting it in the code. 

Yes, I know it is verbose. I tried to cut it down. I will do so more.
I am afraid this is the generation gap: I would prefer to leave as much information in the code itself since network access may not be always available.
I suppose this is the different attitude of "before/after the web" generations.

>>+// This I did after I tried to use nsIErrorService by re-defining
>>+// NS_ERROR_GET_CODE() and NS_ERROR_GET_MODULE() in javascript anyway
>>+// and failed.  It is attempted inside
>>+// getErrMsgFromIErrorService(module_code, error_code).

>As you've discovered, nsIErrorService is mostly not useful - nothing useful >actually registers with the service, and there are no existing users, and so >it's not really suitable for use here. We should really just remove it, since I >don't think we're going to extend its use. I will file a separate bug on doing >this.

OK, I took it out. nsIErrorService is a premature good idea which not many people used then.

 
>>+// run grep NS_ERROR_FILE mozilla/xpcom/base/nsError.h | awk '{printf("// case  %s : msg = \"%s\" ; break; \n", substr($4, 1, length($4)-1), $2)}'
>>+// to obtain the template for the following code.

>These instructions seem out of date now... looks like this stuff is in >xpcom/base/ErrorList.h now?

Right. Updated the comment though once the routine is created, how this is produced is irrelevant. But again, the source of the constants ought to be
clearly visible, and so I updated the comment and made sure that the proper template could be generated.

>>+function myownIOErrorString(code) {
>
>This helper function seems useful, and would be good to put in a JS module. >Maybe in FileUtils.jsm.

I believe that this function (and extended ones to retrieve a short English
message from system error codes ) would be very useful.
I am not sure which FileUtils.jsm file you mention.
I checked and there are two files with such name under comm-central. 
I am not sure if FileUtils.jsm is the right choice, but I have no idea about this. Anyway, the function is there and so can be moved to another file later and
nsHelperAppDlg.js can be modified accordingly.

My first priority right now is to get this patch out to fix this really nasty bug.

>>+function getErrMsgFromIErrorService(module_code, error_code)
>
>As mentioned, I think you should just remove this from the patch.

Did so.

>>+function mydump(msg)
>
>As Paolo mentioned a while ago, this should also be removed.

Well, for this function, I enclosed it in #if 0/#endif pair.
This is because I found this function SO useful in debugging javascript.
(I am not sure what is the status of javascript debugger right now. During
my debugging efforts I saw a debugger getting out of sync with the thunderbird development and dumping variables here and there was the most vialble method unfortunately and mydump() here proved its worth. 
The particular information about the output not visible easily was not documented
in web pages very well. So I think this function has the merit of
staying here within "#if 0/#endif" block.

Well, of course, we can possibly remove this and leave a reference to a URL, but
again I am from the "before the web" generation.

>>+    // We enclose the processing to catch (previously uncaught) errors.
>
> I think we need to be careful to only wrap the sections that would potentially > throw the errors we're concerned about in the try/catch. The existing patch >just puts a whole big block of code in the try/catch, and that can be confusing.

I agree with you in general.
Basically, all I did was to make sure that, where relevant errors are thrown,
I insert try/catch construct so that the error is caught and examined.
I am throwing non-handled error immediately and so there should be no clipped error handling functionality IMHO.
The problem with the old code and its coding style was we never could tell what errors, if any, were thrown. By using try/catch and verbose comment, I hope that
there is now enough documented clue to what is going on in this file (at least
for the interactive saving operation. I still don't understand what goes on
ONCE the save button is hit.)

If you can tell me which try/catch is offensive I can possibly modify it one by one.


>>+    catch (ex)  {  // Coping with I/O errors: We had an error exception.
>>+                   // Show an error message.

>This code should probably be simplified to just be:
>
>let errorMsg = FileUtils.getMessageFromResult(ex.result);
>this.displayError(errorMsg);
>
>or somesuch.

I tried to modify the patch in this direction.
Right now, I simply moved the code that displays the error messages out of
the  function, |PromptToSaveForFile| and names it as "display_error_my_own" and pass the exception to it.
How unimaginative. But this is a work-in-progress patch. 
We can massage these routines into something that interfaces with functions in
an external file (maybe FileUtils.jsm) in the future.

Now the comments to Comment 86:


>>+  displayOtherErrorAlert: function(msg) {
>
>>+    prompter.alert(this.dialog,
>>+                   "I/O Error (saving a file or an attachment)", // Shown in window frame/pane
>>+                   msg);

>This will need to be a localized string, similar to how >displayBadPermissionAlert does it.

I am not sure of the proper steps to do this. I hope this won't take a long time, but I recall reading about the freezing of string bundle before releases.
Anyway, tips about how to get such message localized will be appreciated.
(I do hope, though, this won't delay pushing this patch out much longer.)

>>         // Do not store the last save directory as a pref inside the private browsing mode
>>+        // (This condition is checked  inside gDownloadLastDir.setFile.)
>>         gDownloadLastDir.setFile(aLauncher.source, newDir);
>
> This comment should probably just be removed.

At least, I took my addition here.

> One thing that might also be useful is to focus on simplifying the patch,  >where possible. We don't necessarily need to be exhaustive about detailing the >specific reasons for the failures in all cases, as long as we have suitable >default behavior for handling "generic" failures. Depending on how likely these >cases are hit in practice, it may be better to take a simpler approach.

Again, in general terms I agree with you.
However, I had too much time on my hands while this patch lingered on in bugzilla. The more I looked at the original code, the more problems I found with it and this is why the patch has bloated to this stage.
The current processing is what I would have for a semi rock-solid mail-client (although I would have done away with the superficial check for writability in advance since this is race-prone and not so much useful.)
Also, I used the term "semi" because I found so many places in the code base where the return value of lower-level function is not checked :-(
This lack of checking of return value (or in this particular file, the failure to catch the error thrown) will haunt TB for years, but I digress.

Anyway, here is the much streamlined patch along with your suggestion although
it still has verbose comment and functions are not quite polished yet.

TIA
Additional comment:
Because of my patch was created long time ago, and my current 
source tree is a few weeks old, I may have screwed up when I tried to modify the
file using more up-to-date source tree on a different PC.

The patches near
(old line) 373 - (new line) 847,
517            -           1003,
537            -           1013,

may not be quite right. I will look into them.

TIA
(In reply to :Gavin Sharp (use gavin@gavinsharp.com for email) from comment #85)
> Comment on attachment 601242 [details] [diff] [review]
> 1st patch slightly cleaned up.
> 
> Chiaki - thank you for taking the time to prepare these patches, and for
> being persistent despite the delays. I'm apologize that I have not been
> responsive here. Generally the overall approach seems good, though the
> patches will need a good amount of "cleaning up" before they are ready to be
> committed. Here are some comments on this patch: 

Dear Gavin and all,

I am cloning this bug to another one:

The reason is as follows:
 - the relevant file, nsHelperAppDlg.js has undergone a major transition to
   ASYNC Javascript API, and the source looks a different now: (It uses async TASK
   processing.)
 - also, there was a discovery that there TWO different code paths( one that is invoked
   when user clicks on the attachment and is handled by JS code, and the other
   that uses [SAVE] button at the lower-right corner of the screen and is handled basically
   by .cpp code alone.) and I need to focus one at a time, and

 - as Gavin noted the patch accumulated many small patches over time, with 
   comments that address discoveries of new bugs and features all along,
   it needs cleaning up. A major surgery may be in order.

So I have decided to clone this bug and start afresh so that the
patch can be implemented in a following manner (more or less).

Since the
code has been modified to use the new Java ASYNC API, and thus
it is a good opportunity to start afresh.

---------
////////////////////////////////////////
// Strategy for fix
//
// (A) bare minimum.: Important, Dataloss, etc.
//     Show error when the saving fails (due to write-permission problems, etc.)
//
// (B) Use of of myownIOErrorString() for better I/O error reporting
// other than access permission issues.
//
// (C) Caution about the racy-check done by IsUsableDirectory(), and
//     that is why the code below it needs try{} catch() {} protection.
//
// (D) Issue of the usage of this file by TB and FF.
//     The default save location differs (and see (5) below).
//
// (E)	Addressing philosophical issue of using two different code paths for
//	clicking on the attachment, and [save] button on the
//	lower-right corner. The default save position is
//	different for both modes of operation, and may be confusing.
---------


Thank you for your patience to cope with these comments and the fluid patches, but
the core issue of the failure to warn the user when the saving of an attachment to 
a write-protected directory is so serious that it warrants FIXING NOW IMHO.
(Actually, I put my modified nsHelperAppDlg.js in MY OWN copy of linux for a while to cope
with the problem, but it has become too much bother to do so due to the fundamental change in the distributed code.)

So I said to myself even if the distributed code addresses only 80 % of my concern, it should be
distributed widely.

TIA
Blocks: 928250
Attachment #705863 - Flags: review?(gavin.sharp)
No longer blocks: 30784, 700114, 928250
Status: ASSIGNED → RESOLVED
Closed: 11 years ago
No longer depends on: 549719
Resolution: --- → DUPLICATE
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: