Rewrite nsMsgSend in JS
Categories
(MailNews Core :: Composition, task, P2)
Tracking
(thunderbird_esr78 wontfix, thunderbird83 wontfix)
People
(Reporter: jcranmer, Assigned: rnons)
References
(Blocks 1 open bug, Regressed 1 open bug)
Details
Attachments
(30 files, 40 obsolete files)
(deleted),
patch
|
Details | Diff | Splinter Review | |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
text/plain
|
Details | |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
mkmelin
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
rnons
:
review+
|
Details | Diff | Splinter Review |
Comment 1•9 years ago
|
||
Reporter | ||
Comment 2•9 years ago
|
||
Updated•6 years ago
|
Updated•5 years ago
|
Updated•5 years ago
|
Comment 3•4 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #0)
As I see it, nsMsgSend comprises basically three loosely-dependent but atomic steps of a pipeline:
- From input values, produce the top-level headers, and collect all of the bodies, attachments, and inline images into a uniform representation.
- Convert said representation into a MIME blob.
- Send that MIME blob over SMTP/NNTP/to a folder/etc. as desired.
As Joshua mentions further down in his comment #0, there is also nsIMsgComposeSecure, so at some stage the data needs to be run through encryption. Maybe that happens after step 2 and encryption replaces one "MIME blob" with another.
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 4•4 years ago
|
||
This patch adds a MessageSend.jsm and pipes to nsMsgSend, the goals of this patch are:
- Everything should work as before
- When using
MOZ_NEW_MSG_SEND=1 ./mach run
, the js implementation ofcreateAndSendMessage
will be used, and should be able to send plain and/or html text mail
Next steps will be:
- Handle attachments
- Handle encryption
- Details and things I'm not aware of yet
Everything seems good, except test_temporaryFilesRemoved.js
is failing. The reason is after wrapping nsMsgSend inside MessageSend.jsm, the destructor of nsMsgSend is not run as fast as when using nsMsgSend directly. Haven't found a workaround yet.
Assignee | ||
Updated•4 years ago
|
Reporter | ||
Comment 5•4 years ago
|
||
This patch has quite a few issues, some major and some minor, so let me first focus on those higher-level issues before delving into minutiae.
The biggest issue I have here is that I don't see any sense of a design for the rewrite. Looking at this patch, I have a hard time seeing what you envision the code will look like once we kill off the old code; how will the various stages be organized in their constituent classes/functions; what kind of API that's not the monstrosity of nsIMsgSend will look like. That's the design part that's lacking here, and I believe it would behoove us to nail down the design before going off and doing much implementation.
A related note is the plan for this implementation. When I proposed essentially one big code drop, I was too focused on making changesets be atomic "feature-complete" changesets rather than actually finding ways to make small changes that make sense. I want to push you to do a large-set-of-small-change approach here, and a sketch of what that would start with is:
- Add a JS implementation that handles the fallback mechanism, and does nothing else.
- Gather the features implied by all of the prefs that are hidden somewhere in the process--and fallback if the implementation doesn't support them yet (which it obviously won't at this stage!).
- Change the compose tests to be able to test both the old and new implementation.
- Now add support for plain text emission. No format=flowed support, no del=sp, no non-UTF-8 charset support, just the most basic plain text output. For now, we'll send via the old implementation.
- Add format=flowed support.
- Add HTML support (but don't support embedded images!)
- Add support for regular attachments
- And now cloud attachments
- And embedded images
- How about some multipart/alternative support?
- Encryption might happen now.
- Wouldn't it be nice to attach an email?
- Ooh, let's start handling send stuff in JS now. And this probably requires multiple patches of course!
I'm not going to insist on that particular set of changes, but that should give you an idea of the kind of plan I'd like to see for these changes.
I'm not a fan of how the fallback works in this patch. An approach that may work better is to try to use the JS implementation, and fallback to the old C++ implementation if it requires an unsupported feature (this is why I had patch 2 in my above listed sequence). Combine this with a mechanism to force the old or new implementation as well (which works especially well for testing--the tests can run twice, once with forcing old and once with forcing new).
Reporter | ||
Comment 6•4 years ago
|
||
Assignee | ||
Comment 7•4 years ago
|
||
Hi, thanks for the review.
The biggest issue I have here is that I don't see any sense of a design for the rewrite
The overall roadmap is in comment 4. Let me try to rephrase it a bit
- the current patch: introducing MessageSend.jsm, and fallback to nsMsgSend.cpp, support html and/or plain text
- support attachments
- support encryption
- other things I'm not aware yet
I'm learning by doing right now, I'm not exactly clear what will be involved in the next steps.
- Change the compose tests to be able to test both the old and new implementation.
Do you mean test the old and new separately? From a user's perspective, there is just one version. In the current patch, the tests are testing nsMsgSend.cpp wrapped inside MessageSend.jsm. When it's ready in a few months, tests will be testing MessageSend.jsm only.
I explained above one way to handle the fallback, which is not the way you've chosen to do it here. Were you to do the fallback method you're doing here
this._send = Components.classesByID["{935284E0-C5D8-11d2-8297-000000000000}"]
.createInstance(Ci.nsIMsgSend);
Yes, I saw Components.classesByID
in your prototype patch, but it doesn't seem to exist anymore. https://searchfox.org/mozilla-central/search?path=&q=classesByID returns anything. That's why I think two contractids are needed. I can change the old one to `define NS_MSGSEND_CONTRACTID0 "@mozilla.org/messengercompose/send;0", is that better?
I am not a fan of using environment variables for this sort of thing; it's actually amazingly user-hostile to pass things around via this out-of-band channel.
The general trend at Mozilla, I believe, has been to use hidden prefs to trigger this sort of thing.
Compile time env vars seems common in our code base. Like this https://searchfox.org/comm-central/source/mail/base/modules/MailConstants.jsm#13-18. But it takes a long time to rebuild after toggling a compile time env. That's why I'm using a runtime env here.
This code is incorrect for handling the feature set it's apparently claiming to support. But it's also not going to generalize well to supporting the features that need to be supported.
Is it only the content-type
incorrect, or are there other things incorrect? Yes, I'm aware this needs to be changed when handling attachments. I'm going to introduce something similar to the MimePart
in your prototype patch and nsMsgSendPart
in the next patch.
So if the user specifically requests additional headers, she doesn't get them because you only grab a precious few headers from the compose fields?
Do you mean I should extract all the headers from comp fields? Will update.
Aside from the testing and fallback mechanism, I guess my roadmap is not too different from yours. Do you think changing the old contract id to define NS_MSGSEND_CONTRACTID0 "@mozilla.org/messengercompose/send;0"
is good? Or maybe there are other approaches?
Comment 8•4 years ago
|
||
For testing "both version", see what we do for ical.js: https://searchfox.org/comm-central/search?q=calendar.icaljs&path=&case=false®exp=false
(Also does dynamic registration of one or the other calendar library)
Assignee | ||
Comment 9•4 years ago
|
||
(In reply to Magnus Melin [:mkmelin] from comment #8)
For testing "both version", see what we do for ical.js: https://searchfox.org/comm-central/search?q=calendar.icaljs&path=&case=false®exp=false
(Also does dynamic registration of one or the other calendar library)
Thanks, didn't know xpcom can be dynamically registered.
So this patch adds a MsgSendModuleLoader.jsm
, that doesn't do anything by default, but will load MessageSend.jsm
when a pref value is true.
Reporter | ||
Comment 10•4 years ago
|
||
(In reply to Ping Chen (:rnons) from comment #7)
The overall roadmap is in comment 4. Let me try to rephrase it a bit
- the current patch: introducing MessageSend.jsm, and fallback to nsMsgSend.cpp, support html and/or plain text
- support attachments
- support encryption
- other things I'm not aware yet
A roadmap is not a design. The design I am looking for is the skeleton API of what the final product should look like: which classes will need to exist, who will be responsible for handling various steps of the process, what parameters need to be passed around, etc.
I'm learning by doing right now, I'm not exactly clear what will be involved in the next steps.
Please stop writing code for the moment and spend a few days just reading through the existing code and taking notes on the features it supports and some of the ways it goes about doing things. Then think about how the design should look to implement those features (although note that we don't want to continue supporting all features--multipart/apple-double for example we're likely to drop). Only once you have that first draft of a design should you start to go about writing the code. I'm saying this to try to save you hours of time.
I do realize that our compose code is dilapidated and cruddy, and that it can be hard to follow. If you need help, ping me in #maildev on matrix and I can try to respond as quickly as I'm available. (Or others might be able to answer your question as well).
Do you mean test the old and new separately? From a user's perspective, there is just one version. In the current patch, the tests are testing nsMsgSend.cpp wrapped inside MessageSend.jsm. When it's ready in a few months, tests will be testing MessageSend.jsm only.
The old and new versions will have to coexist for some time. While they coexist, it is necessary to test both. (And some time can be a long time; ical.js has been meant to replace libical for over 7 years now!).
Yes, I saw
Components.classesByID
in your prototype patch, but it doesn't seem to exist anymore. https://searchfox.org/mozilla-central/search?path=&q=classesByID returns anything.
I'm going to have to do some more research here... It may be advisable simply to do the choose-which-one in C++ code rather than JS, since C++ definitely can construct by CID instead of contractID.
Is it only the
content-type
incorrect, or are there other things incorrect? Yes, I'm aware this needs to be changed when handling attachments. I'm going to introduce something similar to theMimePart
in your prototype patch andnsMsgSendPart
in the next patch.
I don't know; I didn't spend the time to enumerate all the problems. If you're going to rip the code out shortly anyways, why should I bother trying to understand all the issues? This is why I am pushing you hard to do a design first: it will help you understand what you need to do, and you won't have to write (and I won't have to review) incorrect code.
Comment 11•4 years ago
|
||
Well many times just taking it one step at a time to see what needs to happen is the only feasible route.
Trying to understand it all beforehand is asking a lot. Of course there will be iterations. Especially since it's off by default until everything is working, I don't see a problem with that.
Assignee | ||
Comment 12•4 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #10)
A roadmap is not a design. The design I am looking for is the skeleton API of what the final product should look like: which classes will need to exist, who will be responsible for handling various steps of the process, what parameters need to be passed around, etc.
Maybe we have different understanding of this task. In my opinion the task is rewriting, the skeleton api will still be nsIMsgSend. I think you mentioned on matrix that you don't like 18 arguments got passed to createAndSendMessage
, but I don't think it's good to change it in this task.
Please stop writing code for the moment and spend a few days just reading through the existing code and taking notes on the features it supports and some of the ways it goes about doing things. Then think about how the design should look to implement those features (although note that we don't want to continue supporting all features--multipart/apple-double for example we're likely to drop). Only once you have that first draft of a design should you start to go about writing the code. I'm saying this to try to save you hours of time.
I've already spent a few days reading the existing code and your prototype patch. I tried to understand every line of the code, but it doesn't seem to work for me. I don't think I can form a design different from nsIMsgSend by reading the existing code, but after I implement all the interfaces of nsIMsgSend in JS, I should have better idea. So I changed my mind to start with porting createAndSendMessage
, try to support sending html/plain message as the first step, and fill in missing pieces step by step.
The old and new versions will have to coexist for some time. While they coexist, it is necessary to test both. (And some time can be a long time; ical.js has been meant to replace libical for over 7 years now!).
I was only aware of ical.js and libical yesterday, my new patch should support that, do you mind taking a look?
Is it only the
content-type
incorrect, or are there other things incorrect? Yes, I'm aware this needs to be changed when handling attachments. I'm going to introduce something similar to theMimePart
in your prototype patch andnsMsgSendPart
in the next patch.I don't know; I didn't spend the time to enumerate all the problems. If you're going to rip the code out shortly anyways, why should I bother trying to understand all the issues? This is why I am pushing you hard to do a design first: it will help you understand what you need to do, and you won't have to write (and I won't have to review) incorrect code.
I'm going to adapt the code to support attachments, not throw it away. By introducing a MimePart
class with a Write function (https://searchfox.org/comm-central/source/mailnews/compose/src/nsMsgSendPart.cpp#378), I still need to build the final message not too different from string concatenation. Getting the most basic html/plain text message right will help me with the next step.
BTW, my new patch in comment 9 is roughly the first item in your roadmap:
- Add a JS implementation that handles the fallback mechanism, and does nothing else.
I will send a patch that supports html/plain message after that.
Assignee | ||
Comment 13•4 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #10)
A roadmap is not a design. The design I am looking for is the skeleton API of what the final product should look like: which classes will need to exist, who will be responsible for handling various steps of the process, what parameters need to be passed around, etc.
It just came to my mind that the the internal structure of MessageSend.jsm will become much more clear when supporting attachments. I haven't figured out how attachments are handled, and I don't want to put too much stuff in one patch. That's why I did the html/plain message as a separate patch. It helped me understand how a RFC822/RFC2045 message looks like. If we can get things right for html/plain text only message first, then we have less things to worry about in the next steps.
I don't trust my design if I can't see sending/receiving message actually works in TB. It will help me a lot if you can bare with me for the first two patches. We can discuss more with the actual code in the planned third patch, in which I will handle attachments.
Comment 14•4 years ago
|
||
As a pointer, note that there is https://searchfox.org/comm-central/rev/5edba8a2dd51172df411fbac749d944a9c65dae2/mailnews/db/gloda/modules/MimeMessage.jsm#354 which may be of relevance
Assignee | ||
Comment 15•4 years ago
|
||
This patch partially supports sending text message without any attachments. Content-Transfer-Encoding
is missing right now. I will add a pickEncoding
function and encode the body text when necessary in the next patch.
Assignee | ||
Updated•4 years ago
|
Reporter | ||
Comment 16•4 years ago
|
||
If you learn best by implementing code, that is totally fine and I have no issues with you doing that. If you need to implement the code in the context of Thunderbird to get that practical experience, again I have no objections. If you need more experience before you can develop a design, yet again, I will not object.
But to review a project of this magnitude, I do need that design. And I believe it would be a better use of both your time and my time were you to go ahead and complete your learning experiences without trying to work those patches for review. When you have those modifications done, then you should be able to complete a better design, and we can discuss that. And it may be that you can reuse a lot of your prior code; it may be that you cannot use it. Don't feel bad about throwing away code; I know I've got at least two or three attempts at rewriting this code in the past, even if most of them have never even graced a review comment.
Reporter | ||
Comment 17•4 years ago
|
||
Reporter | ||
Comment 18•4 years ago
|
||
Reporter | ||
Comment 19•4 years ago
|
||
Assignee | ||
Comment 20•4 years ago
|
||
This patch uses the categories
field in components.conf
.
(In reply to Joshua Cranmer [:jcranmer] from comment #18)
I'm in the middle of moving comm-central to static component registration in
bug 1652354, which will likely have knock-on effects for the registration
here.
Are you worrying there will be lots of conflicts? I didn't change the registration of any existing components. Seems to me the only conflict will be in the components.conf
file.
(I think there's more work that needs to be done to be able to
override contract IDs in static component registration). I don't believe
it's worth appraising this patch before that code is ready.
The approach in this patch is the same as calBackendLoader.js
, which loads ical.js dynamically. And it seems to work. Please tell me what more I need to do.
Assignee | ||
Comment 21•4 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #19)
Comment on attachment 9166755 [details] [diff] [review]
Think about what you need to do for 8-bit, non-UTF-8 parts...
... because JS strings are likely to cause you to do the wrong thing.
Can you enlighten me what do you mean 8-bit, non-UTF-8 part? And what is the problem of using JS string?
And it seems clear to me that you really love using JS's string formatting,
but in the long run, you are probably better off using Uint8Array instead of
strings.[This is an example of why I want to see a design up-front: you could
potentially convince me otherwise that strings instead of Uint8Array are
going to be OK for this code, but convincing is going to be very difficult
without enough of a design to indicate to me that you've thought through the
implications.]
In my opinion, this is about details/things I'm unaware of. If I don't know using JS string is a problem, how would my design avoid it? I use JS string because it works so far. If you point out the problems, I would sure change to Uint8Array if necessary. And I already mentioned "I will add a pickEncoding function and encode the body text when necessary in the next patch." in comment 15.
Assignee | ||
Comment 22•4 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #19)
Comment on attachment 9166755 [details] [diff] [review] [diff] [review]
Think about what you need to do for 8-bit, non-UTF-8 parts...
... because JS strings are likely to cause you to do the wrong thing.
I think I understand the problem better now, it's not that JS can't represent 8-bit non-UTF-8 chars, but it becomes incorrect after converting back and forth, especially TextEncoder only supports UTF-8. So this patch stores 8-bit string in MimePart directly to avoid converting. I think string is more suitable than Uint8Array, because there is no .concat
method of Uint8Array, I will need to use something like new Uint8Array([...a, ...b])
to combine two arrays. I also need to convert headers and part separator to Uint8Array. The code will be difficult to read and easy to make mistakes.
The more I work on this bug, the more details I know. I don't worry about the design, I worry about all kinds of cases. When I submitted the first patch, I didn't even know foramt=flowed
only applies to text/plain
. After adding class MimePart
in this patch, and class MimeEncoder
on my local, I'm satisfied with the design, I believe it can handle attachments without big change. Thank you for pointing out things I don't know.
Comment 23•4 years ago
|
||
Comment 24•4 years ago
|
||
Assignee | ||
Comment 25•4 years ago
|
||
Updates according to comment 23.
- use
Components.Exception
- Remove the
a
prefix from argument names
Assignee | ||
Comment 26•4 years ago
|
||
Updates according to comment 24.
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
Can use OS.Constants.Path.tmpDir and use the OS.File (or OS.Path) operators to get the file path. I don't think it needs to be created, you should just call writeAtomic directly.
The purpose is to create a unique file, similar to https://searchfox.org/comm-central/source/mailnews/compose/src/nsMsgCompUtils.cpp#84. I guess it's safer this way to avoid two TB instances operating the same file? I will change if you think it's unnecessary. I also changed to use OS.File.openUnique
, which seems more efficient than nsIFile.createUnique
.
Updated•4 years ago
|
Comment 27•4 years ago
|
||
Assignee | ||
Comment 28•4 years ago
|
||
Updates according to comment 27.
+ .msgGenerateMessageId(this._userIdentity); + } + let headers = new Map([ + ["Message-Id", messageId], + ["Date", new Date()],
this is not quite the mail date formatting
My understanding is jsmime will handle the date formatting. https://searchfox.org/comm-central/source/mailnews/mime/jsmime/jsmime.js#3464
Assignee | ||
Comment 29•4 years ago
|
||
This patch adds a class MimeEncoder
, that mainly provides two functions
pickEncoding
: determine the Content-Transfer-Encoding valueencode
: apply base64 or quoted-printable encoding to the body ofMimePart
MimeEncoder
will also be used to handle attachments in the next patch.
Reporter | ||
Comment 30•4 years ago
|
||
(In reply to Ping Chen (:rnons) from comment #22)
I think I understand the problem better now, it's not that JS can't represent 8-bit non-UTF-8 chars, but it becomes incorrect after converting back and forth, especially TextEncoder only supports UTF-8. So this patch stores 8-bit string in MimePart directly to avoid converting. I think string is more suitable than Uint8Array, because there is no
.concat
method of Uint8Array, I will need to use something likenew Uint8Array([...a, ...b])
to combine two arrays. I also need to convert headers and part separator to Uint8Array. The code will be difficult to read and easy to make mistakes.
No. Thinking about the problem as concatenation--string or Uint8Array--is the wrong way to think about the problem. What you're doing is streaming a series of bytes to an output. This output may itself be a transformer, for example someone who is converting it into base64 or quoted-printable text, or maybe someone streaming it into an encryption algorithm to support encrypted messages. Or the target may simply be an output file. Or maybe you're piping it directly into a network connection. In any case, at no point would you be directly concatenating bytes together. As a bonus, at no point do you need to hold an entire copy of the message in memory.
The more I work on this bug, the more details I know. I don't worry about the design, I worry about all kinds of cases.
I worry about all kinds of cases, including weird edge conditions. And that's why I worry about the design: I need to see that the design handles all of the cases--and in lack of a design, I at least need confidence that you are at least worrying about all of them too. But I don't have that confidence here, and your replies have so far not been giving me confidence.
Reporter | ||
Comment 31•4 years ago
|
||
Let me start by apologizing for the length of this comment. It is a wall of text, but I don't think I can express what needs to be expressed without making it a wall of text. Please read all of it before moving to respond to any part.
I have concerns about the design of the rewrite that you are proposing. Getting the design right from the beginning is crucial; bad design has a way of leaking through APIs and spreading through the codebase. Furthermore, people and projects are usually extremely reluctant to tackle fixing bad design: it's easier to build yet another workaround rather than taking the time to rip out bad design.
An example of bad design in mailnews code that has infected beyond its initial APIs is that we store unparsed, rather than parsed, headers in our database, and so all the clients must parse them, which opens up inconsistencies if they don't use the correct API (and it's not easy to do so!).
In rewriting the code, we have a great opportunity to fix the design, especially since we can look back onto the existing code and evaluate design decisions that worked and those that didn't work. We do not need to rely on guesses as to how well the design will scale to future uses, when the uses are pretty well-known.
From my perspective, when I see your code, I have no prior experience to draw on to estimate how good you are at planning for future design. All I can do is extrapolate from the code you have written and from your replies to my review comments. If I were satisfied that you understood the design issues and could come up with a good design, I would not be pushing for a more formal design.
To be blunt: I did not like your design from the first patch, and your comments since then have only strengthened that assessment. Without confidence that you will be able to carry through this process through the end, it is hard for me to justify the immense time sink of thoroughly checking the existing code to understand what is and isn't being regressed.
Let's talk issues in more detail now. I'm not sure I've covered all of the issues in this list, but here they are as they cross my mind:
-
API design. As I mentioned in the beginning of this bug, the current interface of nsIMsgSend is a bad interface design and needs to be replaced with something better. While the new interface does need to be the last step of a very long sequence of patches, it is a good idea to design to a new interface from the beginning. To that end, I expect to see the code implemented in a way that is not so strictly tied to needing to support the current API. I'd actually expect much of the work to exist outside of a
MessageSend
class. -
Blind reimplementation of existing code. This is a problem I've seen more with your later patches: there appears to be some copying of decisions from existing C++ code that is wrong and needs to be fixed, rewrite or not. An example here is the use of charsets influencing the type of encoding to use... just no. Now this doesn't mean that there isn't wisdom in existing code that can and should be ported, but it does require understanding the code, understanding why it's doing what it's doing, and then deciding if those reasons are still valid.
-
Using strings for binary data. I realize that JS has really poor facilities for handling binary data, especially compared to its string libraries. But my historical experience is that using (nominally) Unicode strings for binary data is a route that only leads to problems down the line. I've mentioned this in my previous comment, but the way you get around array concatenation is by changing the API so that you never need to actually concatenate arrays. Indeed, even having to do a concatenation of any kind in this context is a code smell.
-
Strings in other contexts. You're using a string to represent content-type, including parameters instead of a data structure that will serialize to the string value, but gives the necessary parameters in an easier format. Considering that you're already going to have to worry about RFC 2231 encoding parameters and writing that out anyways, it makes sense to convey other content-type parameters in a similar manner. In general, strings are bad data types, and you should only convert to strings at the last possible moment.
-
File size and method size. I have a personal distaste for large files--I think code is optimally sized at no more than 1000-ish lines of code per file. So when code starts greatly exceeding that size, I would want to see it broken up into smaller pieces. I envision there being roughly three major stages here at the end: a low-level MIME assembly file, a low-level actual sending phase, and an orchestration component that mediates between the input parameters and the low-level phases. I suggest you separate these phases into separate JS files.
-
Error handling. JS code is pretty notorious for causing errors to be thrown in unexpected places, much more so than our C++ code. The direct implementation of nsIMsgSend needs to have a relatively thin intermediary layer that will catch and propagate errors as needed to the listeners, else things like tests tend to hang without any clear indication why.
-
Tests. Our current test coverage is actually kind of crappy, especially when it comes to ensuring corner cases are handled correctly. I'd expect any rewrite to be adding a lot more tests. I'd also actually expect some of the existing tests to have to be rewritten, because they have a nasty habit of being too specific to particular details that need not be kept (e.g., line break locations in encoded messages).
Now let's talk about next steps.
I don't want to see any more code for the moment; I'm not happy with the current design, and I want to make sure that we can agree on how the code should work before you spend more time pursuing a design that will only be rejected.
You've mentioned that you worry about all kind of cases. I think the best next step for us to take is to put together a list of all the existing features, features to add in the future, and features to remove from the current implementation. To that end, I'm attaching an incomplete list that should give you a starting point. Note that the list is incomplete: it's entirely based on what I can recall from memory after 15 minutes or so, and it has been quite some time since I went through compose code with a fine-toothed comb.
After that, the next step would be to put together what nsIMsgSend
should look like if we weren't constrained to implement the current interface. This is the main essence of why we are rewriting the code: if we are not going to improve on what exists, then rewriting is just a waste of time that will introduce yet more bugs and regressions into our codebase.
As part of that, we also need to understand what new interfaces we should add to reduce code duplication. There are a few other places where we build MIME messages, and adding a new interface to support those use cases is a good idea to me.
Only once those steps are completed do I believe it is worth taking the time to actually look at the implementation of code.
Reporter | ||
Comment 32•4 years ago
|
||
Assignee | ||
Comment 33•4 years ago
|
||
In addition to comment 29, this patch:
- split out
MimePart
andMimeEncoder
to separate files - add a
write
method toMimePart
so no need to hold the whole message in memory
Blind reimplementation of existing code. This is a problem I've seen more with your later patches: there appears to be some copying of decisions from existing C++ code that is wrong and needs to be fixed, rewrite or not. An example here is the use of charsets influencing the type of encoding to use... just no. Now this doesn't mean that there isn't wisdom in existing code that can and should be ported, but it does require understanding the code, understanding why it's doing what it's doing, and then deciding if those reasons are still valid.
I didn't know converting the existing C++ code to JS would be a problem, I still don't what's the problem of using charset to pick encoding, I will think about it. In the meantime, it seems safer for me to just copy the behavior of existing C++ code.
Using strings for binary data.
I changed to write out immediately, instead of holding the whole message in memory, is that better?
Strings in other contexts. You're using a string to represent content-type, including parameters instead of a data structure that will serialize to the string value, but gives the necessary parameters in an easier format. Considering that you're already going to have to worry about RFC 2231 encoding parameters and writing that out anyways, it makes sense to convey other content-type parameters in a similar manner. In general, strings are bad data types, and you should only convert to strings at the last possible moment.
Shouldn't this be handled by jsmime?
File size and method size.
MimePart
and MimeEncoder
are split into separated files in this patch.
I don't want to see any more code for the moment; I'm not happy with the current design, and I want to make sure that we can agree on how the code should work before you spend more time pursuing a design that will only be rejected.
Please tell me the problems of the current design so I can fix. I don't have enough knowledge to discuss with you on the big picture. The current approaching of rewriting bit by bit seems to work best for me.
After that, the next step would be to put together what nsIMsgSend should look like if we weren't constrained to implement the current interface. This is the main essence of why we are rewriting the code: if we are not going to improve on what exists, then rewriting is just a waste of time that will introduce yet more bugs and regressions into our codebase.
I think it's an improvement if by rewriting, the data flow becomes cleaner, the code becomes easier to make changes. I believe many of the problems you pointed out (e.g. charset used in pickEncoding) can be fixed in a very local place. And I'm thinking about enabling some tests in the next two patches. I'd like to know what are the critical design flaws of MessageSend
, MimePart
and MimeEncoder
.
Comment 34•4 years ago
|
||
Comment 35•4 years ago
|
||
Comment 36•4 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #31)
Clearly the original API isn't ideal, but if we not kind of copy things fairly directly, making the both implementations live side by side until we're further down the road doesn't seem very possible.
Reporter | ||
Comment 37•4 years ago
|
||
(In reply to Magnus Melin [:mkmelin] from comment #36)
(In reply to Joshua Cranmer [:jcranmer] from comment #31)
Clearly the original API isn't ideal, but if we not kind of copy things fairly directly, making the both implementations live side by side until we're further down the road doesn't seem very possible.
Implementing the current API in terms of a new API is likely quite possible; I've done in that in prior rewrite attempts with no issues whatsoever.
Assignee | ||
Comment 38•4 years ago
|
||
Updates according to comment 34. Added jsdoc docs to MimePart, will add more in the future.
Assignee | ||
Comment 39•4 years ago
|
||
Updates according to comment 35.
Assignee | ||
Comment 40•4 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #31)
Now let's talk about next steps.
I don't want to see any more code for the moment; I'm not happy with the current design, and I want to make sure that we can agree on how the code should work before you spend more time pursuing a design that will only be rejected.
You've mentioned that you worry about all kind of cases. I think the best next step for us to take is to put together a list of all the existing features, features to add in the future, and features to remove from the current implementation. To that end, I'm attaching an incomplete list that should give you a starting point. Note that the list is incomplete: it's entirely based on what I can recall from memory after 15 minutes or so, and it has been quite some time since I went through compose code with a fine-toothed comb.
After that, the next step would be to put together what
nsIMsgSend
should look like if we weren't constrained to implement the current interface. This is the main essence of why we are rewriting the code: if we are not going to improve on what exists, then rewriting is just a waste of time that will introduce yet more bugs and regressions into our codebase.As part of that, we also need to understand what new interfaces we should add to reduce code duplication. There are a few other places where we build MIME messages, and adding a new interface to support those use cases is a good idea to me.
Only once those steps are completed do I believe it is worth taking the time to actually look at the implementation of code.
Sorry I'm not convinced this is the only and best way to approach this task. It seems to me most of my code are not directly related to nsIMsgSend
, for those that do, they are for the purpose of connecting with the existing code, so I can send/receive emails for testing. If it helps, I can split the current MessageSend
to say class MsgSend
and class MessageSend
, MsgSend
implements nsIMsgSend
and MessageSend
will be a new class with new interfaces. They might still be tightly coupled and limited by nsIMsgSend
at first.
Why can't we fix problems one by one? For example, I added a write
method to replace toString
yesterday, is it better now? Or can we delay it and fix other problems first?
Assignee | ||
Comment 41•4 years ago
|
||
As mentioned in comment 40, this patch splits out a class MimeMessage
from MessageSend.jsm
. MessageSend
is the class that implements nsIMsgSend
, MimeMessage
has more flexibility. And in long terms, we may want to replace nsIMsgSend
with MimeMessage
.
Updated•4 years ago
|
Updated•4 years ago
|
Comment 42•4 years ago
|
||
Comment 43•4 years ago
|
||
Will land these for easier iteration in tree
Comment 44•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/587fde4c6cd0
Init MsgSendModuleLoader and MessageSend to prepare for rewriting nsMsgSend. r=mkmelin
https://hg.mozilla.org/comm-central/rev/6c4eb4fc78a3
Partial support of sending text message in MessageSend.jsm. r=mkmelin
https://hg.mozilla.org/comm-central/rev/2253cbe6d5e5
Add MimeEncoder class to pick encoding and encode message in MessageSend.jsm. r=mkmelin DONTBUILD
Comment 45•4 years ago
|
||
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 46•4 years ago
|
||
Updates according to comment 45:
- Move
EXPORTED_SYMBOLS
to the top - Fix
@param
comment
Assignee | ||
Comment 47•4 years ago
|
||
This patch supports sending local attachments.
I've made some progress on the configs to run a test for both nsMsgSend.cpp and MessageSend.jsm, but seems most tests rely on the Draft folder, which MessageSend.jsm doesn't support yet. So I will work on that in the next patch, and remove charset and delsp according to bug 862292.
Comment 48•4 years ago
|
||
Assignee | ||
Comment 49•4 years ago
|
||
Updates according to comment 48.
Maybe MimeMultiPart should be a subclass of MimePart, and the "init" would happen automatically/passed in to the constructor?
Good suggestion, I think this approach can be applied to attachment part and main part as well. So there will be classes like MimePartBase, MimeMultiPart, MimeMainPart and MimeAttachmentPart. I will play with this idea when handling cloud attachment. Thanks.
Assignee | ||
Updated•4 years ago
|
Comment 50•4 years ago
|
||
I'll add a Cu.importGlobalProperties(["fetch"]);
to MimePart.jsm make eslint happy
Comment 51•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/d204b1fe63f9
Split out MimeMessage class from MessageSend.jsm. r=mkmelin
https://hg.mozilla.org/comm-central/rev/def8329e7a26
Support local attachments in MessageSend.jsm. r=mkmelin
Assignee | ||
Comment 52•4 years ago
|
||
- Remove charset handling following bug 862292
- Support saving to the Draft folder
- Run test_messageHeaders against both nsMsgSend.cpp and MessageSend.jsm
I'm aware the handling of bcc/fcc is incomplete in this patch, I will improve it later by enabling more tests or adding new tests if necessary.
Assignee | ||
Updated•4 years ago
|
Assignee | ||
Updated•4 years ago
|
Comment 53•4 years ago
|
||
Assignee | ||
Comment 54•4 years ago
|
||
+ * @param aMsgSendObj The nsIMsgSend instance that listens to copy events`
Or is this really the nsIUrlListener?
I believe it's nsIMsgSend, they are tightly coupled.
https://searchfox.org/comm-central/source/mailnews/compose/src/nsMsgCopy.cpp#120
https://searchfox.org/comm-central/source/mailnews/compose/src/nsMsgCopy.cpp#58,64,70
+ try { + isCharsetMultiByte = + manager.getCharsetData(this._charset, ".isMultibyte") == "true"; + } catch {}
But charset is always UTF-8 now isn't it, so is this needed?
I think for text/*
attachments, we still need to use pickCharset
to detect the charset, and pass it to the MimeEncoder.
+ let cloudParts = []; + let localParts = [];
Why not just parts? Is there difference in the final ordering that you want?
Added inline comments. The C++ version handles cloud attachments first, so the tests expect cloudParts first. https://searchfox.org/comm-central/source/mailnews/compose/test/unit/test_messageHeaders.js#523,549
+ "\n": "%0A", + "\r": "%0D", + };
Where to these come from? Please add a code comment. Why not just encodeURI?
From https://searchfox.org/comm-central/source/mailnews/compose/src/nsMsgCompUtils.cpp#729-736. Related test is here https://searchfox.org/comm-central/source/mailnews/compose/test/unit/test_messageHeaders.js#434-435. encodeURI
will do more than needed, <
will become %3C
+ if (col >= 38) {
What is this about.
According to https://tools.ietf.org/html/rfc2557#section-4.4.2, the folding *can be* done, using the algorithm defined in [URLBODY](rfc2017) section 3.1.
. And RFC2017 says URL-word Must not exceed 40 characters in length
. But RFC2557 says can be
, not must be
, so I removed the 40 chars limit, and leave it to be folded by jsmime.
+ value += transformMap[char] || char; + } + return `"${value}"`;
seems odd to return a quoted string.
Agreed, I also found bug 151031. I don't find quote is required in rfc2557, so I removed it and updated tests.
+ if (/[\x80-\xff]/.exec(dupParamValue)) { + needsEscape = true; + dupParamValue = Services.io.escapeString(
encodeURIComponent?
In this case, encodeURIComponent
doesn't do as much as Services.io.escapeString
, the related test is https://searchfox.org/comm-central/source/mailnews/compose/test/unit/test_messageHeaders.js#415-417, notice .txt
is percent encoded as well. I guess when actually sending mail, encodeURIComponent
should work as well, but then I would need to change the C++ and tests code.
It seems if two headers are closely related, get them from the same util function can save some code. There is this function https://searchfox.org/comm-central/source/mailnews/compose/src/nsMsgCompUtils.cpp#313-315 that gets two header values at the same time. To split them, I would need to write the same code twice.
I generally prefer {x, y} = func()
than [x, y] = func()
, I feel object keys are more stable than array index. I need to be more careful about the orders both when returning array and destructuring the array.
Assignee | ||
Comment 55•4 years ago
|
||
Perhaps we can remove Content-Base
and only keep Content-Location
? According to https://tools.ietf.org/html/rfc2557#section-2.2
Content-Base This header was specified in RFC 2110, but has been removed in this new version of the MHTML standard.
Assignee | ||
Comment 56•4 years ago
|
||
- Remove
Content-Base
and only keepContent-Location
- Break down two functions to return one header only
- Rename helper functions for
X-header**
togetXHeader**
- Fix a few jsdocs
Assignee | ||
Comment 57•4 years ago
|
||
- Enable
test_saveDraft.js
by implementinggetXMozillaStatus
andgetXMozillaStatus2
- Enable
test_detectAttachmentCharset.js
by implementingpickCharset
- Enable a few other tests without changing code
Comment 58•4 years ago
|
||
Comment 59•4 years ago
|
||
Comment 60•4 years ago
|
||
Assignee | ||
Comment 61•4 years ago
|
||
+ headers.set("X-Mozilla-News-Host", newshost);
should this be lower-case?
To avoid confusion and duplicated header, I changed all header names to lowercase.
let formatFlowed = Services.prefs.getBoolPref(
I'd just check this in the if clause.
And rename formatParams to format (it's only ever one now)
formatFlowed
is used again a few lines below. I renamed formatParams
to formatParam
.
void setCharAttribute(in string name, in ACString value);
Hmm, I think you'd then also need to update the setter to take AUTF8String...
I reverted this change, found that I can use getUnicharAttribute
instead, https://searchfox.org/comm-central/source/mailnews/base/public/nsIMsgIdentity.idl#248-252. I guess one function is enough for getUnicharAttribute
and getCharAttribute
, but I'm not going to touch it in this patch.
Assignee | ||
Comment 62•4 years ago
|
||
Updates to comment 60.
Assignee | ||
Updated•4 years ago
|
Assignee | ||
Comment 63•4 years ago
|
||
- Enable test_attachment by rfc2047 encoding the
name
, while rfc2311 encoding thefilename
param - Enable some other tests without changing code
There seems to be three modes of mail.strictly_mime.parm_folding
https://searchfox.org/comm-central/source/mailnews/compose/test/unit/test_attachment.js#47-51. Is RFC 2047 without folding still relevant? Seems jsmime will always fold, to make the test passes I only kept RFC2047WithCRLF
and RFC2231
in this patch.
Comment 64•4 years ago
|
||
Comment 65•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/41824ba64913
Enable test_messageHeaders for MessageSend.jsm. r=mkmelin
https://hg.mozilla.org/comm-central/rev/5fafcb896ef7
Enable test_saveDraft and test_detectAttachmentCharset for MessageSend.jsm. r=mkmelin DONTBUILD
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 66•4 years ago
|
||
(In reply to Magnus Melin [:mkmelin] from comment #64)
::: mailnews/compose/test/unit/test_attachment.js
@@ +19,1 @@"`abcdefghijklmnopqrstuvwxyz{|}~.txt";
what are these changes about?
The problem is the leading whitespace in the filename (whitespace inside might trigger similar problem as well). With
var input1 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
,
jsmime will format it to
Content-Disposition: attachment; filename*0="
!\\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ";
While the C++ will format it to
Content-Disposition: attachment;
filename*0=" !\\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ";
jsmime split header value with space first, then try to fit a line word by word. I don't see an easy fix to this, one solution might be doing rfc2311 encoding inside jsmime, but that would be a big change.
Comment 67•4 years ago
|
||
Updated•4 years ago
|
Comment 68•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/0922c9a141ad
Enable test_attachment for MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Assignee | ||
Comment 69•4 years ago
|
||
- Enable test_sendBackground by implementing sendMessageFile
- Enable test_sendMessageLater3 by transforming some NS_ERRORs
- Enable some other tests
Assignee | ||
Comment 70•4 years ago
|
||
In test_sendBackground.js, I had to use two nsIMsgSend instances, because sendMessageFile
is an async function in the JS implementation. If sendMessageFile
is immediately called twice on the same nsIMsgSend instance, the second call will overwrite the internal state of the first call.
Comment 71•4 years ago
|
||
Assignee | ||
Comment 72•4 years ago
|
||
+ newExitCode = MsgUtils.generateNSError(12589);
What are the magic numbers? If there's no defined constant accessible, add a code comment about what it refers to.
Changed to newExitCode = MsgUtils.NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_SERVER;
for better readability.
+ new TextEncoder().encode(`From - ${new Date().toUTCString()}\r\n`)
This date format is not exactly what we use I believe. But I don't know if we really use it for anything either.
The date string is designed to be parsed by PR_ParseTimeString, which supports many formats, and I tested it can parse toUTCString()
. On the other hand, I think there is a bug in nsParseMailbox.cpp. This envelope line is not parsed correctly, and the date is never used.
Assignee | ||
Comment 73•4 years ago
|
||
- Enable test_sendMessageFile by calling
notifyListenerOnStopCopy
at the right moment - Enable test_autoReply by using
writeBinaryString
for MimePart - Enable other tests, only five tests left in -cpp.ini now
I have to use two empty catch blocks in this patch. In C++,
if (mListener != nullptr)
mListener->OnStopSending(aMsgID, aStatus, aMsg, returnFile);
return NS_OK;
Non zero return of OnStopSending is not a problem, since it's ignored. However, in JS,
if (this._sendListener) {
this._sendListener.onStopSending(msgId, status, msg, returnFile);
Non zero return of onStopSending will become an exception after going through XPConnect, to ignore the exception, I use try with an empty catch block.
Comment 74•4 years ago
|
||
Comment 75•4 years ago
|
||
Comment 76•4 years ago
|
||
(In reply to Ping Chen (:rnons) from comment #73)
if (this._sendListener) { this._sendListener.onStopSending(msgId, status, msg, returnFile);
Non zero return of onStopSending will become an exception after going through XPConnect, to ignore the exception, I use try with an empty catch block.
Generally with listeners, it is a good idea to report exceptions to the console if they occur. Then they can be more easily tracked rather than the exception getting hidden. If there are onStopSending
implementations that are permanently returning non-zero, then maybe they need to be investigated?
Comment 77•4 years ago
|
||
Yes, maybe better to not swallow errors too easily.
Assignee | ||
Comment 78•4 years ago
|
||
Print non-zero return of listeners to console, this only happens in tests so far, but we will see.
Assignee | ||
Updated•4 years ago
|
Assignee | ||
Comment 79•4 years ago
|
||
- Enable test_sendMailAddressIDN.js by encoding mail address before passing to SMTP service
- Enable test_temporaryFilesRemoved.js by reverting back to
nsIFile.createUnique
.OS.File.openUnique
will get a random hash name, which is difficult to test.
All tests except one in mailnews/compose/test/unit
have been enabled for MessageSend.jsm. Will see if I can do the same to the mail/test/browser/composition
folder.
Comment 80•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/8fb018ed386e
Enable test_sendBackground and test_sendMessageLater for MessageSend.jsm. r=mkmelin
https://hg.mozilla.org/comm-central/rev/3c083ed603d8
Enable test_sendMessageFile and test_autoReply for MessageSend.jsm. r=mkmelin DONTBUILD
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 81•4 years ago
|
||
- Setup configs to support running
mail/test/browser/composition
against MessageSend.jsm - Enable
browser_drafts
by implementingget folderUri
- Enable some other tests
Many tests in mail/test/browser/composition
are not directly related to message sending, but I'm going to enable them anyway.
Because the sending process is async, in browser_drafts
, I had to add a sleep(1)
to test_open_draft_again, so that saving to draft can finish before press_delete
. Without the sleep
, the press_delete
happens first, and then saving to draft will create a new message in the draft folder, which breaks later tests. I don't know why I don't need to add sleep
before every press_delete
.
Updated•4 years ago
|
Comment 82•4 years ago
|
||
Updated•4 years ago
|
Assignee | ||
Comment 83•4 years ago
|
||
+ // In order throw any nserror, _deliverMessage can't be declared async.
Grammar error here. Not sure what it's suppose to read
https://searchfox.org/comm-central/source/mailnews/compose/test/unit/test_sendMailAddressIDN.js#128,150 expects to catch exception thrown by sendMessageFile, with async _deliverMessage(){}
, the exception won't be caught in test. Remove the async
only for one test seems not ideal and I didn't find a workaround, so I changed to disable two cases in test_sendMailAddressIDN.js for MessageSend for now.
+ copyFile = Services.dirsvc.get("TmpD", Ci.nsIFile); + copyFile.append("nscopy.tmp");
Seems backwards to revert this just for testing purposes. I think it would be better to adjust the test (maybe just count files, if names are not stable.)
Updated to count files.
Assignee | ||
Comment 84•4 years ago
|
||
Turns out sleep(1)
is unreliable as the tests failed on Try, after looking into browser_drafts again, found that the following code appears in almost every test and is reliable.
utils.waitFor(
() => !cwc.window.gSaveOperationInProgress && !cwc.window.gWindowLock,
"Saving of draft did not finish"
);
So I moved it into head.js and used it after SaveAsDraft.
Comment 85•4 years ago
|
||
Assignee | ||
Comment 86•4 years ago
|
||
+ // Because sendMessageFile is an async function in MessageSend.jsm, exception + // can't be caught by DoSendTest.
Could you change this test file to split up the 4 cases to use add_task instead. Then everything is checked async and the test could work?
My comment was a bit misleading, the problem was sendMessageFile
is sync according to nsIMsgSend.idl, but when an exception is thrown by an async function called inside sendMessageFile
, the exception can't be caught by tests.
This patch updates nsIMsgSend.idl to return Promise from sendMessageFile
, then uses add_task
in test_sendMailAddressIDN.js. I put this in a separate patch because this is my first time using Promise in xpidl, I worry it may break something unexpected. A Try run seems fine: https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=4cd447b8aa83465a957c81d49c01f6
Comment 87•4 years ago
|
||
Assignee | ||
Comment 88•4 years ago
|
||
Due to bug 1665652, I moved test_sendMailAddressIDN.js back to xpcshell-cpp.ini, so it's not ran against MessageSend and I can move on.
Assignee | ||
Comment 89•4 years ago
|
||
Comment on attachment 9175978 [details] [diff] [review]
1211292-part3.6.patch
The original purpose of this patch is to make test_sendMailAddressIDN.js work with MessageSend.jsm. This patch has its value by returning Promise in xpidl, but then I also need to update test_sendMailAddressIDN.js to use add_task
. I will re-submit this patch after bug 1665652.
Comment 90•4 years ago
|
||
Assignee | ||
Updated•4 years ago
|
Comment 91•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/bf07498ab5ca
Init mochitest configs and enable browser_drafts for MessageSend.jsm. r=mkmelin
https://hg.mozilla.org/comm-central/rev/160781d72107
Enable test_temporaryFilesRemoved for MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 92•4 years ago
|
||
- Enabled browser_attachmentReminder.js by implementing the error reporting when sending failed
- Enabled browser_emlActions.js by putting
messageServiceFromURI
in a a try..catch block
Comment 93•4 years ago
|
||
Assignee | ||
Comment 94•4 years ago
|
||
Please document what the 0x80000000 is about.
Maybe best to declare it as a constant somewhere
Added NS_FAILED helper to MsgUtils.
+ let msgHdr = Cc["@mozilla.org/messenger;1"] + .createInstance(Ci.nsIMessenger) + .messageServiceFromURI(originalMsgURI) + .messageURIToMsgHdr(originalMsgURI); + let folder = msgHdr.folder;
Instead of try/catch. To handle .eml messages, you should just check if folder is set. If it's not, it's a standalone .eml
The exception is thrown by messageServiceFromURI
before I can check .folder
, I moved code out of the try block to make it clearer.
Assignee | ||
Comment 95•4 years ago
|
||
Add newline to the end of .ini files.
Comment 96•4 years ago
|
||
Assignee | ||
Comment 97•4 years ago
|
||
Instead of these two, can we just use
Components.isSuccessCode()
?
Thanks, didn't know about isSuccessCode.
Maybe just use Cu.reportError(e) though, like
I feel it can't be considered an error here, so I used console.warn
Assignee | ||
Updated•4 years ago
|
Comment 98•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/13b7004235b7
Enable browser_attachmentReminder and browser_emlActions for MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Assignee | ||
Comment 99•4 years ago
|
||
- Support embedded images
- Enable browser_blockedContent
Comment 100•4 years ago
|
||
Assignee | ||
Comment 101•4 years ago
|
||
Can we avoid passing in an editor. Seems more than a bit wrong... It shouldn't really have anything to do with MimeMessage
Good suggestion, I moved all interaction with editor to MessageSend.jsm and passed embeddedAttachments to MimeMessage.
+ // Convert UTF-16 string back to byte string.
You're all in js here. Is this needed? Looks to me it would happen automatically?
I added more comments. The reason is the body argument of createAndSendMessage is ACString. Also 8-bit string is used in MimeEncoder to pick encoding and do encoding. And when we fetch an attachment, we get the content as 8-bit string. So we handle message body text the same way as attachment content.
Comment 102•4 years ago
|
||
Assignee | ||
Comment 103•4 years ago
|
||
There are some test failures on treeherder related to this. Is this going to clear those up?
Yes, except for test_autoReply. Did a Try run earlier today, https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=849e0e6adcf8f363d1717538a3375c&selectedTaskRun=MDfxv4S0Q0G-UcWeueIIsQ.0 only test_autoReply failed in win10 debug build.
Maybe use use a real Map()
Plain object seems more light weight to me, I renamed it to urlCidCache
Assignee | ||
Comment 104•4 years ago
|
||
- Support forwarding as attachment
- Enable browser_forwardHeaders.js and other forwarding tests.
Try run: https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&selectedTaskRun=D9t94zvyQaSaDQEhUqNkPw.0&revision=b83339f8aa9f4ed9f9d2e985113b705f79815194
The lint error already fixed.
Comment 105•4 years ago
|
||
Comment 106•4 years ago
|
||
Comment 107•4 years ago
|
||
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 108•4 years ago
|
||
- Add
attribute AUTF8String contentId
to nsIMsgAttachment and fix forwarding as attachment - Enable remaining composition mochitests
- Enable test_sendMailAddressIDN.js
Will work on cases not covered by existing tests: like collecting addresses to address book, or sending to newsgroup.
Comment 109•4 years ago
|
||
Updated•4 years ago
|
Comment 110•4 years ago
|
||
Pushed by geoff@darktrojan.net:
https://hg.mozilla.org/comm-central/rev/f4e236a8735f
Enable remaining composition mochitests for MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Assignee | ||
Comment 111•4 years ago
|
||
A small patch
- collects outgoing addresses to address book
- shows status message in each step
- passes
mail.sanitize_date_header
pref value toemitStructuredHeaders
Found that when copy operation failed, need to show a dialog with retry button. And need to FilterSentMessage
when copy succeeded, will work on them in the next patch.
Comment 112•4 years ago
|
||
Not sure why, but the most recent patch that landed has increased the amount of memory leaked dramatically. 40% in the case I looked at. It's not because we're running more tests, all of the added tests are run separately. Log of a task that ran the C++ version. Log of a task that ran the JS version.
Now that the JS version of this code is running all of the tests, that test run is also reporting more memory leaked than our threshold.
Assignee | ||
Comment 113•4 years ago
|
||
Folder name can be empty, fix unit tests.
Comment 114•4 years ago
|
||
Comment 115•4 years ago
|
||
(In reply to Geoff Lankow (:darktrojan) from comment #112)
Not sure why, but the most recent patch that landed has increased the amount of memory leaked dramatically. 40% in the case I looked at.
Ping: please check that patch. It's very non-obvious what it could have caused a leak so probably need to take the patch apart and send a few try runs to compare, until you find the right spot.
Assignee | ||
Comment 116•4 years ago
|
||
Disable three mochitests to fix leak failure. These three tests were already unstable when run with nsMsgSend.cpp, each of them has an intermittent bug. I guess running them twice just make things worse. Two Try runs:
https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=b13873efcc1f21d8717b76d2305826aefc07c0bf
https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=4be3aa999b5a62d20e1d16fec62e990af7e7eb7f (not finished yet)
Will enable debug mode on local and investigate one by one.
Updated•4 years ago
|
Updated•4 years ago
|
Comment 117•4 years ago
|
||
Pushed by geoff@darktrojan.net:
https://hg.mozilla.org/comm-central/rev/405b4dc4dfcd
Disable four tests for MessageSend.jsm. r=mkmelin
https://hg.mozilla.org/comm-central/rev/03fd007540eb
Collect outgoing addresses to address book in MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 118•4 years ago
|
||
- Support retrying on copy failure, manually tested
- Support fcc2 field, add test_fcc2.js
Comment 119•4 years ago
|
||
Assignee | ||
Comment 120•4 years ago
|
||
Rebase and use throw Components.Exception
.
Assignee | ||
Updated•4 years ago
|
Assignee | ||
Comment 121•4 years ago
|
||
- Run filters after sending
- Support sending to newsgroup
Will start working on encryption.
Comment 122•4 years ago
|
||
Pushed by geoff@darktrojan.net:
https://hg.mozilla.org/comm-central/rev/30ca8975fad5
Support retrying on copy failure and support fcc2 in MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Comment 123•4 years ago
|
||
Updated•4 years ago
|
Comment 124•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/69f70e9e5dd4
Run filters after sending, support sending to newsgroup in MessageSend.jsm. r=mkmelin DONTBUILD
Assignee | ||
Updated•4 years ago
|
Assignee | ||
Comment 125•4 years ago
|
||
Support message encryption.
Comment 126•4 years ago
|
||
Assignee | ||
Comment 127•4 years ago
|
||
::: mailnews/compose/src/MessageSend.jsm
@@ +594,5 @@if (this._folderUri.startsWith("mailbox:")) { this._copyFile = Services.dirsvc.get("TmpD", Ci.nsIFile); this._copyFile.append("nscopy.tmp"); this._copyFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); let fileWriter = await OS.File.open(this._copyFile.path, { write: true });
Why this change?
This change is to keep nsemail.eml
and nscopy.tmp
in the same folder, because OS.Constants.Path.tmpDir
is not always the same as Services.dirsvc.get("TmpD"
. Without this change, test_temporaryFilesRemoved.js
will still pass, but doesn't really test nscopy.tmp
.
Services.dirsvc.get("TmpD"
is used for nsemail.eml
because to work with nsIMsgComposeSecure, nsIOutputStream has to be used. Previously, file hanlder from OS.File.openUnique
was used to append to nsemail.eml
.
But I don't know. It doesn't seem like a good API to be passing this in.
Maybe one of the classes should implement nsIMsgComposeSecure (possibly
refactoring, splitting out just the relevant parts of that) so that write
for that class would handle encryption automatically.
I agree the api is not great. But to do beginCryptoEncapsulation
directly in MimePart, all the arguments of beginCryptoEncapsulation
need to be passed to MimePart, which I think is worse than passing a callback. I renamed this callback to startCryptoEncapsulation
to avoid confusion with nsIMsgComposeSecure.beginCryptoEncapsulation.
Comment 128•4 years ago
|
||
How about creating a SecureMimeMessage class inherting from MimeMessage. SecureMimeMessage would override createMessageFile and possibly something else. The write() method only does something different for the top part anyway so maybe the logic to do encryption/signing could just be in MimeMessage.createMessageFile as well?
Updated•4 years ago
|
Assignee | ||
Comment 129•4 years ago
|
||
The current flow is
- MimeMessage.createMessageFile
- (top)MimePart.write(Headers)
- MimeMessage.startCryptoEncapsulation
- MimePart.write (recursively write out child parts and top part body)
Because it's interleaved, I followed the C++ code to pass startCryptoEncapsulation
as a callback to MimePart.
A new SecureMimeMessage
class doesn't seem to help, instead I suggest moving the write function from MimePart to MimeMessage. The new flow will be
- MimeMessage.createMessageFile
- MimeMessage.writePart(topPart)
Then inside MimeMessage.writePart
- write top headers
- startCryptoEncapsulation
- recursively write out child parts and top part body
Will update.
Comment 130•4 years ago
|
||
Sounds good. But with this changed, then you could have a SecureMimeMessage class that would handle encrypting, right?
Assignee | ||
Comment 131•4 years ago
|
||
Move write
from MimePart
to MimeMessage
.
But with this changed, then you could have a SecureMimeMessage class that would handle encrypting, right?
Seems to me one MimeMessage
class is enough. True there are a few if..else in createMessageFile
and _writePart
. But with an extra SecureMimeMessage class, I need to decide which class to use in MessageSend
. I can't further split createMessageFile
and _writePart
to smaller reusable functions, so they will be mostly the same in MimeMessage and SecureMimeMessage.
Assignee | ||
Comment 132•4 years ago
|
||
- Show a warning dialog when message file size exceeds
mailnews.message_warning_size
. Because nsMsgCompose will do some cleanup on sending failure https://searchfox.org/comm-central/source/mailnews/compose/src/nsMsgCompose.cpp#1350,1377, I had to runcreateAndSendMessage
synchronously. - Some changes to
xpcshell-cpp.ini
andbrowser-cpp.ini
to prepare for enablingmailnews.send.jsmodule
globally.
mailnews.send.jsmodule
is enabled globally in this Try run https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=7f30537d6298fd19c837f9e608537a24a5d0634d, two tests failed, will fix them in the next patch.
Updated•4 years ago
|
Comment 133•4 years ago
|
||
Assignee | ||
Comment 134•4 years ago
|
||
Added some comments.
Hopefully I can remove syncPromise
in the next patch. Learned about DomPromiseListener
https://searchfox.org/mozilla-central/source/dom/promise/PromiseNativeHandler.h#49-50 today, will use it to resolve Promise in C++.
Comment 135•4 years ago
|
||
Assignee | ||
Comment 136•4 years ago
|
||
Added a message to Components.Exception
Assignee | ||
Updated•4 years ago
|
Comment 137•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/7ff7b0021034
Support message encryption in MessageSend.jsm. r=mkmelin
https://hg.mozilla.org/comm-central/rev/eae99a0ccada
Show a warning dialog for large message file in MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Comment 138•4 years ago
|
||
Returns Promise in nsIMsgSend and nsIMsgCompose.
(In reply to Magnus Melin [:mkmelin] from comment #87)
::: mailnews/compose/src/nsMsgSendLater.cpp
@@ +504,5 @@true, // bool deleteSendFileOnCompletion, false, // bool digest_p, nsIMsgSend::nsMsgSendUnsent, // nsMsgDeliverMode mode, nullptr, // nsIMsgDBHdr *msgToReplace, sendListener, mFeedback, nullptr, getter_AddRefs(promise));
I do think this is basically misuse of c++ promise. But if it works maybe we
don't care, especially as this code will be going away once we're done.I mean, you're not rejecting the promise on errors. This is now c++ side not
an async function really, but instead a sync function and since an error
will cause an exception it kind of works out? A more correct use would
proably involve adding some implicit_jscontext.
In this case, we are not passing any useful info through the promise, everything still go through listeners, so I ignored the Promise.
In this patch, only CreateAndSendMessage
passes a nsresult
through Promise, the other changes are to make it compile and consistent.
Comment 139•4 years ago
|
||
Assignee | ||
Comment 140•4 years ago
|
||
promise.forget(aPromise);
I think promise can easily be null
I think it's fine as long as aPromise
is not null, https://searchfox.org/mozilla-central/source/mfbt/RefPtr.h#270. I tested it works when promise
is null.
if (NS_FAILED(rv)) NotifyStateListeners(nsIMsgComposeNotificationType::ComposeProcessDone, rv);
Would this get invoked?
Seems SendMsgToServer
is never used directly, so I moved them into SendMsg
.
// ----" string, which is kinda misleading. TODO: Should // there be a "really no header" option?
odd folding here. I think we can remove the TODO
Reverted unrelated changes by clang-format, don't know how it happened. I ran clang-format
again and no such changes.
Updated•4 years ago
|
Assignee | ||
Updated•4 years ago
|
Comment 141•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/5c87be1d969d
Return Promise in nsIMsgSend and nsIMsgCompose. r=mkmelin DONTBUILD
Comment 142•4 years ago
|
||
The last push breaks Windows:
0:10.71 z:/Mozilla/comm-central/comm/mailnews/mapi/mapihook/src/msgMapiHook.cpp(340,62): error: too few arguments to function call, expected 6, have 5
0:10.71 pMsgId, nullptr, nullptr, nullptr);
0:10.72 ^
0:10.72 z:/Mozilla/TB/dist/include\nsIMsgCompose.h(341,36): note: 'SendMsg' declared here
0:10.72 JS_HAZ_CAN_RUN_SCRIPT NS_IMETHOD SendMsg(MSG_DeliverMode deliverMode, nsIMsgIdentity *identity, const char * accountKey, nsIMsgWindow *aMsgWindow, nsIMsgProgress *progress, ::mozilla::dom::Promise * * _retval) = 0;
Comment 144•4 years ago
|
||
Comment on attachment 9181748 [details] [diff] [review]
bug1211292_sendMsgPromise.patch
No, I get a:
1:30.92 In file included from z:/Mozilla/comm-central/comm/mailnews/mapi/mapihook/src/msgMapiHook.cpp:10:
1:30.93 In file included from z:/Mozilla/TB/dist/include/nsCOMPtr.h:29:
1:30.93 z:/Mozilla/TB/dist/include/mozilla/RefPtr.h(50,38): error: member access into incomplete type 'mozilla::dom::Promise'
1:30.93 static void Release(U* aPtr) { aPtr->Release(); }
1:30.94 ^
1:30.94 z:/Mozilla/TB/dist/include/mozilla/RefPtr.h(381,62): note: in instantiation of member function 'mozilla::RefPtrTraits<mozilla::dom::Promise>::Release' requested here
1:30.94 static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
1:30.94 ^
1:30.94 z:/Mozilla/TB/dist/include/mozilla/RefPtr.h(81,37): note: in instantiation of member function 'RefPtr<mozilla::dom::Promise>::ConstRemovingRefPtrTraits<mozilla::dom::Promise>::Release' requested here
1:30.94 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
1:30.94 ^
1:30.94 z:/Mozilla/comm-central/comm/mailnews/mapi/mapihook/src/msgMapiHook.cpp(339,33): note: in instantiation of member function 'RefPtr<mozilla::dom::Promise>::~RefPtr' requested here
1:30.94 RefPtr<mozilla::dom::Promise> promise;
1:30.94 ^
1:30.94 z:/Mozilla/TB/dist/include/nsrootidl.h(25,7): note: forward declaration of 'mozilla::dom::Promise'
1:30.95 class Promise;
1:30.95 ^
1:30.95 1 error generated.
Comment 145•4 years ago
|
||
Thanks for checking! I backed it out - https://hg.mozilla.org/comm-central/rev/ea4dbc2fb9b9e0ea31b3c2013769731a2c6cb3d8
Assignee | ||
Comment 146•4 years ago
|
||
Updated msgMapiHook.cpp to build on Windows.
+ #include "mozilla/dom/Promise.h"
+ RefPtr<mozilla::dom::Promise> promise;
rv = pMsgCompose->SendMsg(WeAreOffline() ? nsIMsgSend::nsMsgQueueForLater
: nsIMsgSend::nsMsgDeliverNow,
pMsgId, nullptr, nullptr, nullptr,
+ getter_AddRefs(promise));
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Updated•4 years ago
|
Assignee | ||
Updated•4 years ago
|
Comment 147•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/592fb5c396eb
Return Promise in nsIMsgSend and nsIMsgCompose. r=mkmelin
Updated•4 years ago
|
Assignee | ||
Comment 148•4 years ago
|
||
- Fix browser_ext_compose_onBeforeSend.js when run with MessageSend.jsm
- Fix browser_filelinkTelemetry.js when run with MessageSend.jsm
- Remove some unused code
When MessageSend.jsm is enabled globally, all tests pass now.
https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=7e31c1e4d33086117bceb578916440
Comment 149•4 years ago
|
||
Updated•4 years ago
|
Comment 150•4 years ago
|
||
Pushed by thunderbird@calypsoblue.org:
https://hg.mozilla.org/comm-central/rev/feeeaae233ae
Fix browser_ext_compose_onBeforeSend.js when run with MessageSend.jsm. r=mkmelin
Updated•4 years ago
|
Comment 151•4 years ago
|
||
Backed out for test failures in comm/mail/test/browser/cloudfile/browser_filelinkTelemetry.js:
https://hg.mozilla.org/comm-central/rev/92f9ece20d5775d6f42d938b330c2307b6f20b03
Updated•4 years ago
|
Assignee | ||
Comment 152•4 years ago
|
||
Fix browser_filelinkTelemetry.js with
+ let sendPromise = BrowserTestUtils.waitForEvent(cwc.window, "aftersend");
cwc.click(cwc.eid("button-send"));
- await BrowserTestUtils.waitForEvent(cwc.window, "aftersend");
+ await sendPromise;
Comment 153•4 years ago
|
||
Assignee | ||
Comment 154•4 years ago
|
||
Renamed the promise. It passed on my local, I was confident it will pass on Try. Last time, I only tested with MessageSend.jsm enabled globally.
Pushed to Try just now, https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=c31075927c9f7d7e42aaba6512c489491c151612
Assignee | ||
Updated•4 years ago
|
Comment 155•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/a23c5e6f23cb
Fix browser_ext_compose_onBeforeSend.js when run with MessageSend.jsm. r=mkmelin DONTBUILD
Updated•4 years ago
|
Assignee | ||
Comment 156•4 years ago
|
||
Enable test_sendMailAddressIDN.js again for MessageSend.jsm, previously it failed in debug mode.
Comment 157•4 years ago
|
||
Please reference a successful try run for all platforms (-p all)
Assignee | ||
Comment 158•4 years ago
|
||
Updated•4 years ago
|
Comment 159•4 years ago
|
||
Assignee | ||
Comment 160•4 years ago
|
||
- Fix QP encoding for trailing whitespace
- Add test_messageBody.js
Assignee | ||
Updated•4 years ago
|
Comment 161•4 years ago
|
||
Assignee | ||
Comment 162•4 years ago
|
||
- Rename
char
toch
- Add a test case for non-ascii text
Comment 163•4 years ago
|
||
Updated•4 years ago
|
Comment 164•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/e17e6a8f62f0
Fix QP encoding for MessageSend.jsm. r=mkmelin DONTBUILD
Updated•4 years ago
|
Assignee | ||
Comment 165•4 years ago
|
||
It's about time to test MessageSend.jsm with real use. This patch enables MessageSend.jsm for nightly build, please help me land it when you see fit.
A note about the memory leak problem found in comment 112, and three mochitests disabled for MessageSend.jsm in comment comment 116.
Bytes leaked when run in local debug build.
test file | cpp | jsm |
---|---|---|
browser_drafts.js | 24309888 | 24342968 |
browser_newmsgComposeIdentity.js | 13427512 | 13401336 |
three mochi tests together | 34861084 | 34926332 |
The three tests work fine when running for cpp or jsm separately. But when moving them into browser-shared.ini
, Try server will report test failure caused by memory leak. I have no idea how to decrease the memory leak, I'm not going to investigate it further in this bug.
Comment 166•4 years ago
|
||
Can parties working on this patch take a look at Bug 1673288, especially
the bug 1673288 comment 1 there?
https://bugzilla.mozilla.org/show_bug.cgi?id=1673288#c1
Assignee | ||
Comment 167•4 years ago
|
||
Update sendDeliveryCallback
and the fcc process to follow the C++ code closely.
Comment 168•4 years ago
|
||
Assignee | ||
Comment 169•4 years ago
|
||
Renamed newExitCode to exitCode.
why this change? Js send always creating CRLF? Should it? If it really should, please add a code comment
Yes, valid mail should always use CRLF. The \n\n
seems to be added by ConvertBufToPlainText
, I think the current behavior is due to it's an xpcshell test. When a window instance is available, the final mail won't contain \n\n
.
Try link: https://treeherder.mozilla.org/#/jobs?repo=try-comm-central&revision=eec4888d138e7cfc163dc1301f5e67
Comment 170•4 years ago
|
||
Assignee | ||
Comment 171•4 years ago
|
||
Updated comment in test_longLines.js.
Assignee | ||
Updated•4 years ago
|
Comment 172•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/9bd688d14fbd
Fix sendDeliveryCallback and doFcc in MessageSend.jsm. r=mkmelin
Assignee | ||
Updated•4 years ago
|
Comment 173•4 years ago
|
||
Comment 174•4 years ago
|
||
Let's do follow-up work in other bugs, to ease tracking.
Comment 175•4 years ago
|
||
Pushed by mkmelin@iki.fi:
https://hg.mozilla.org/comm-central/rev/a3f9fbf593ee
Enable MessageSend.jsm in nightly builds (mailnews.send.jsmodule true). r=mkmelin
Updated•4 years ago
|
Assignee | ||
Updated•4 years ago
|
Updated•4 years ago
|
Comment 176•3 years ago
|
||
(In reply to Joshua Cranmer [:jcranmer] from comment #31)
Let me start by apologizing for the length of this comment. It is a wall of text, but I don't think I can express what needs to be expressed without making it a wall of text. Please read all of it before moving to respond to any part.
I have concerns about the design of the rewrite that you are proposing. Getting the design right from the beginning is crucial; bad design has a way of leaking through APIs and spreading through the codebase. Furthermore, people and projects are usually extremely reluctant to tackle fixing bad design: it's easier to build yet another workaround rather than taking the time to rip out bad design.
An example of bad design in mailnews code that has infected beyond its initial APIs is that we store unparsed, rather than parsed, headers in our database, and so all the clients must parse them, which opens up inconsistencies if they don't use the correct API (and it's not easy to do so!).
In rewriting the code, we have a great opportunity to fix the design, especially since we can look back onto the existing code and evaluate design decisions that worked and those that didn't work. We do not need to rely on guesses as to how well the design will scale to future uses, when the uses are pretty well-known.
From my perspective, when I see your code, I have no prior experience to draw on to estimate how good you are at planning for future design. All I can do is extrapolate from the code you have written and from your replies to my review comments. If I were satisfied that you understood the design issues and could come up with a good design, I would not be pushing for a more formal design.
To be blunt: I did not like your design from the first patch, and your comments since then have only strengthened that assessment. Without confidence that you will be able to carry through this process through the end, it is hard for me to justify the immense time sink of thoroughly checking the existing code to understand what is and isn't being regressed.
Let's talk issues in more detail now. I'm not sure I've covered all of the issues in this list, but here they are as they cross my mind:
API design. As I mentioned in the beginning of this bug, the current interface of nsIMsgSend is a bad interface design and needs to be replaced with something better. While the new interface does need to be the last step of a very long sequence of patches, it is a good idea to design to a new interface from the beginning. To that end, I expect to see the code implemented in a way that is not so strictly tied to needing to support the current API. I'd actually expect much of the work to exist outside of a
MessageSend
class.Blind reimplementation of existing code. This is a problem I've seen more with your later patches: there appears to be some copying of decisions from existing C++ code that is wrong and needs to be fixed, rewrite or not. An example here is the use of charsets influencing the type of encoding to use... just no. Now this doesn't mean that there isn't wisdom in existing code that can and should be ported, but it does require understanding the code, understanding why it's doing what it's doing, and then deciding if those reasons are still valid.
Using strings for binary data. I realize that JS has really poor facilities for handling binary data, especially compared to its string libraries. But my historical experience is that using (nominally) Unicode strings for binary data is a route that only leads to problems down the line. I've mentioned this in my previous comment, but the way you get around array concatenation is by changing the API so that you never need to actually concatenate arrays. Indeed, even having to do a concatenation of any kind in this context is a code smell.
Strings in other contexts. You're using a string to represent content-type, including parameters instead of a data structure that will serialize to the string value, but gives the necessary parameters in an easier format. Considering that you're already going to have to worry about RFC 2231 encoding parameters and writing that out anyways, it makes sense to convey other content-type parameters in a similar manner. In general, strings are bad data types, and you should only convert to strings at the last possible moment.
File size and method size. I have a personal distaste for large files--I think code is optimally sized at no more than 1000-ish lines of code per file. So when code starts greatly exceeding that size, I would want to see it broken up into smaller pieces. I envision there being roughly three major stages here at the end: a low-level MIME assembly file, a low-level actual sending phase, and an orchestration component that mediates between the input parameters and the low-level phases. I suggest you separate these phases into separate JS files.
Error handling. JS code is pretty notorious for causing errors to be thrown in unexpected places, much more so than our C++ code. The direct implementation of nsIMsgSend needs to have a relatively thin intermediary layer that will catch and propagate errors as needed to the listeners, else things like tests tend to hang without any clear indication why.
Tests. Our current test coverage is actually kind of crappy, especially when it comes to ensuring corner cases are handled correctly. I'd expect any rewrite to be adding a lot more tests. I'd also actually expect some of the existing tests to have to be rewritten, because they have a nasty habit of being too specific to particular details that need not be kept (e.g., line break locations in encoded messages).
Now let's talk about next steps.
I don't want to see any more code for the moment; I'm not happy with the current design, and I want to make sure that we can agree on how the code should work before you spend more time pursuing a design that will only be rejected.
You've mentioned that you worry about all kind of cases. I think the best next step for us to take is to put together a list of all the existing features, features to add in the future, and features to remove from the current implementation. To that end, I'm attaching an incomplete list that should give you a starting point. Note that the list is incomplete: it's entirely based on what I can recall from memory after 15 minutes or so, and it has been quite some time since I went through compose code with a fine-toothed comb.
After that, the next step would be to put together what
nsIMsgSend
should look like if we weren't constrained to implement the current interface. This is the main essence of why we are rewriting the code: if we are not going to improve on what exists, then rewriting is just a waste of time that will introduce yet more bugs and regressions into our codebase.As part of that, we also need to understand what new interfaces we should add to reduce code duplication. There are a few other places where we build MIME messages, and adding a new interface to support those use cases is a good idea to me.
Only once those steps are completed do I believe it is worth taking the time to actually look at the implementation of code.
Is Joshua Cranmer still around? He had some good information here.
Updated•3 years ago
|
Reporter | ||
Comment 177•3 years ago
|
||
(In reply to Worcester12345 from comment #176)
Is Joshua Cranmer still around? He had some good information here.
I'm mostly active only in the Matrix chat right now.
Description
•