-
-
Notifications
You must be signed in to change notification settings - Fork 373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple bugs in TnefPart.cs #538
Comments
I somehow managed to stumble onto a solution to earlier issue where I wasn't getting the RecipientType for every row in the Recipient Table. Somehow, when I included a case for RowId and read the property, I was able to retrieve each row correctly and get the corresponding RecipientType. So now, code looks like this for ExtractRecipientTable:
|
The reason adding prop.ReadValueAsInt32() works is because there is presumably a bug in TNEF is, unfortunately, very difficult to debug w/o test cases which are hard to come across :( I've committed the RowId fix. Did that solve all of your issues? It sounds like that also fixed your MapiProperties issue, right? Since presumably the corruption issue is gone now. |
Hi Jeff, That fixed the issue with reading every row in the recipient table correctly. However, it still didn't fix the issue where the MapiProperties was corrupted after that... As a work around, I'm calling both ExtractRecipientTable and ExtractMapiProperties seperately (i.e. I initialize a new TnefReader for each operation), it seems like that is the only reliable way for now... Reusing the TnefReader seems to be unreliable. Is there anyway to do a "reset" on the reader? I've encountered another issue with trying to extract the sender email address from the MapiProperties. When I print out the SenderEmailAddress property, I do not get a string that contains a valid email address. My output is like this: /O=ORG/OU=EXCHANGE (ABCD1234)/CN=RECIPIENTS/CN=1234567890-SOME NAME Looking at the file in a hex editor, I'm actually able to see there is a valid email address somewhere below the Body property, but I can't identify which property that it. On the same line as the sender email address I see some text with the words "Client=MSExchangeRPC". Would you be able to identify which property that is? Thanks! |
Update: I noticed that some properties were not recognized (or perhaps also corrupted?) so I did a default case in the switch statement to print out the raw form of the property:
This is what I discovered: Property: 23818 Do you think this is an issue of corrupted properties? Or just some properties that are not defined in MimeKit? Thanks! |
The Of course, I could be wrong in my understanding, so feel free to fact check me on that ;-) It looks like I don't have a Reset() method on TnefReader, but perhaps I could add one... that said, ideally you wouldn't have to reset, so maybe I'll hold off on adding that until we can figure out the real bug you are hitting. Is there any chance you could send me the winmail.dat file(s) that you are struggling with? Ideally they'd be suitable for me to add to my test suite to prevent bugs like this from cropping up in the future, but I understand if you need them to stay private. I also understand if there's no way you'd even allow me to see them. Back to your problem, though, based on the API that I cloned, it appeared that some properties can have multi-values. Perhaps that is what you are encountering? I don't think I ever managed to find an example winmail.dat file with such a case, though. All that said, it would be interesting if you could figure out if MimeKit's TnefReader/TnefPropertyReader were reading beyond the end of a property or whether it wasn't reading enough - either way would cause the next property to seem corrupted to the reader. What you could try doing us printing out the TnefReader.StreamOffset at the start of each attribute tag. Console.WriteLine("Before reading any TnefAttributeTags, offset = {0}", reader.StreamOffset);
while (reader.ReadNextAttribute ()) {
if (reader.AttributeLevel == TnefAttributeLevel.Attachment)
break;
var prop = reader.TnefPropertyReader;
Console.WriteLine("TnefAttributeTag.{0} properties start at offset {1}", reader.AttributeTag, reader.StreamOffset);
switch (reader.AttributeTag) {
case TnefAttributeTag.RecipientTable:
ExtractRecipientTable (reader, message);
break;
case TnefAttributeTag.MapiProperties:
ExtractMapiProperties (reader, message, builder);
break;
case TnefAttributeTag.DateSent:
message.Date = prop.ReadValueAsDateTime ();
break;
case TnefAttributeTag.Body:
builder.TextBody = prop.ReadValueAsString ();
break;
}
Console.WriteLine("TnefAttributeTag.{0} properties end at offset {1}", reader.AttributeTag, reader.StreamOffset);
} My guess is that in your first pass, immediately after RecipientTable, you'll get a nonsensical TnefAttributeTag (due to reading from a mis-asligned stream offset). I want to compare those offsets in the output from the above loop to the offsets of your second pass to see if RecipientTable is over-reading or under-reading. |
Regarding your update, it could be that the properties are corrupted due to a mis-aligned stream read as well, that would not be surprising. It's also possible that those property values are valid IDs that I just don't have a mapping for. Most of the mappings I've found have been through docs and looking at other tnef readers in java, c, etc - none of which had a complete set. Each project seemed to have a different subset of TNEF property identifiers (with quite a bit of overlap, but mostly only the core properties). |
Heading to bed for now, but if you've got any winmail.dat samples you can send me, that would help tremendously. |
I have been reading and you are encountering x.400 addressing, which has been an internal addressing used by Exchange. What you may find is that there are no IETF addresses on the email if it did not have to bridge from the internal Exchange network to an external mail host. You will also find that the messages or more often the message stores suffer corruption and post a problem. Just my two cents |
@KelvinKingGitHub any news? I'll have a bunch of free time on Sunday to work on this if you've got some sample files to send me. |
@jstedfast I sent an email to your Microsoft address. Did you receive it? I wasn’t sure where else to send. |
@KelvinKingGitHub when did you send it? I don't seem to have it but if it was a few days ago, I might have emptied my Spam folder without realizing your email was mistakenly sitting in there (whatever spam filtering rules Microsoft uses, it seems to filter legit messages into my Spam folder - I usually try to go thru it every few days and catch those messages, but I may have missed yours?) |
@jstedfast I sent it on Fri I think... No worries, I'll send you another email now. |
@KelvinKingGitHub ok, I'll keep an eye out for it. |
BTW, make sure to spell my email alias correctly - it's [email protected] (note that it's not [email protected] which it would seem like it should be). The default rules for creating a Microsoft email alias seems to be first 2 characters of a person's first name and the first 6 characters of their last name. |
@jstedfast Ok, I just sent the email I was just trying to recall what I said in my previous note. Let me know if you received it, or if your spam filter removed the attachment. |
@KelvinKingGitHub I think I just saw your message in my Inbox but as soon as I clicked it in Outlook (for Mac), it disappeared. I wonder if Outlook auto-decoded the winmail.dat or something into whatever the item was and added it to my calendar/tasks/something? |
@jstedfast Would zipping it up work ? |
Yea, that might be the way to go - I can't find it anywhere in Outlook anymore. I wonder if this is what happened to your email sent on Friday as well. |
@jstedfast Possible... I noticed that each mail client has different ways of handling winmail.dats. Did it work now ? |
Yep, I've got it now! Thanks! I'll take a look into this today and see if I can figure out the problem(s). |
Cheers! |
Okay, so I did find/fix some bugs in the TnefPropertyReader logic, but I don't think it has made much of a difference. I didn't find these properties, though:
However, I suspect those were probably in another winmail.dat file and not the one you sent me as a test case. I did find the following properties that I thought were interesting: Recipient Table:
MAPI Properties Table:
I tried searching for 0x00003FFA in https://interoperability.blob.core.windows.net/files/MS-OXPROPS/%5bMS-OXPROPS%5d-190319.pdf and found that 16378 (aka 0x3FFA) seems to map to PidTagLastModifierName. Based on the same document, 24566 (aka 0x5FF6) seems to map to PidTagRecipientDisplayName, so I'll add a mapping for this one. |
23818 (0x5D0A) and 23819 (0x5D0B) don't seem to map to anything, but 23809 (0x5D01) would map to SenderSmtpAddress which would be exactly what we want. |
When advancing to the next row or property, make sure to properly skip over the remaining properties or values. Partial fix for issue #538
The above fix should address the need to read the Rowid property value and I added the mapping for PR_RECIPIENT_DISPLAY_NAME. |
Thanks Jeff. You are correct, the Property: 23818 and 23819 tags were in another email. I was unable to reproduce that in the sample However, 16378 does consistently appear in all my winmail.dat files. So perhaps that's more reliable. 23809 doesn't seem to appear in any of my winmail.dat files. So unfortunately, I can't use that... I'll pull the latest code and test it out. Did it also resolve the issue where the TnefAttributeTag was getting corrupted after reading the Recipient Table? |
Hi Jeff, Regarding the issue with the TnefAttributeTag - it's my bad... I was simply doing a ReadNextAttribute() within my function, so essentially I was skipping the Attribute altogether. |
@KelvinKingGitHub ah, okay, thanks for that update. I was not able to reproduce the TnefAttributeTag corruption bug you had mentioned but thought that maybe it was only a problem with some of the other test cases you had. I added an enum for the 16378 property ( |
BTW, as you continue to work through your TNEF samples, if you find any property id's that you'd like me to add mappings for, let me know and I'll add them. One thing I noticed in the docs is that there is an SenderSmtpAddress property that can be stored in an AttributeTag. I wonder if any of your samples have any AttributeTags other than the RecipientTable and the MapiProperties? |
Thanks Jeff. I don't recall seeing SenderSmtpAddress attribute tag in any of my winmail.dat files. But I'll do another check and update you on that. In the sample I sent you, were you able to extract the attachment within it? I mentioned in my email that I think there might be a bug in the ExtractAttachments also... |
@KelvinKingGitHub I don't have a mapping for the SenderSmtpAddress AttributeTag, so I think it'll appear as an unknown AttributeTag. I was just wondering if any of your samples had an Attribute tag other than RecipientTable and MapiProperties. Hope that clears up any confusion. What was the attachment in the winmail.dat that you sent me? I was able to extract a plain-text body and some RTF data, but didn't see anything else. |
The attachment was a msg that was inline in the body of the email. It appears as an EmbeddedMeasage in the AttachMethod properties. There might be a bug that is preventing it from being extracted correctly. |
Ah, I'll try to take a look tonight. I don't think I had any samples with an EmbeddedMessage before so I probably have some bugs there... |
…Name Another partial fix for issue #538
I thought I committed the PidTagLastModifierName patch the other day, but just noticed that I hadn't |
Added mappings for some PR_ATTACHMENT_XXXX property tags. I also stepped thru the current code and it is extracting an "embedded message" attachment but it was returning a regular MimePart instead of a TnefPart because he AttachMethod property doesn't appear until after getting the AttachData. I'm cooking up a fix for that as well. Is that the last bug that you are aware of? |
Sometimes AttachData can become before AttachMethod, so properly handle this case as well. Another partial fix for issue #538
Hi Jeff, Yup, that's the bug I was referring to. In my case, the AttachMethod comes after AttachData. So the logic couldn't handle this situation... I fixed it on my side by basically duplicating the code into the AttachData switch case as well, and it seemed to work... |
However, now this line: builder.Attachments.Add (attachment); will have a logic error. Because it appears now 2 times in both the case: AttachData and case: AttachMethod, the TnefPart will get added twice to the attachments list. Once when it's treated as a "normal" attachment, and second time when it's recognized as an EmbeddedMessage... |
Right, all I did in my fix that I just committed was to remove the MimePart attachment, convert it into a TnefPart, and then re-add it. |
Can you test out my fixes and see if that solves all of your issues? I'm about to head to bed, but I'll read your comments in the morning and see if I can squeeze in some more fixes tomorrow if they are needed. |
Thanks Jeff, I'll test it out. I also found that it was necessary to remove the first 16 bytes of the attachData when setting the TnefPart content. Here's my code: var stream = new MemoryStream(); |
Ah, interesting... that might make sense because it's probably some type of "object" (where those first 16 bytes may be a GUID or something) when the type is a EmbeddedMessage. Thanks for that info, I didn't even think of checking that. |
I got that clue because you were doing it in the GetEmbeddedMessageReader() from TnefPropertyReader.cs. So it kinda made sense for me to do that same for the AttachMethod code as well. |
…leading GUID Final fix for issue #538
BTW, would it be ok for me to include the tnef file you emailed me in the unit tests? |
Sure. As long as the winmail.dat file itself is not made public. |
Ah, that's the file that I was asking about ;-) Don't worry, it's not a big deal. Most of the code changes are covered by existing files already. I actually discovered that fixing these bugs exposed a bug in my unit tests for a file I created myself using Outlook to create some calendar events I guess. I forgot I did that. Hah! |
@jstedfast I just ran into this old ticket while googling around for some .CFG form inanity in Outlook and I figured it might interest you that Microsoft has explained what these two props do over here: HEX 0x5D0A (DEC 23818) = Creator SMTP Address |
Thanks, I just added those and the PR_SENDER_SMTP_ADDRESS to MimeKit's TnefPropertyId enum. |
I've been working a lot lately with winmail.dat files and discovered multiple bugs in some of the methods in TnefPart.cs:
First function with bugs is ExtractRecipientTable (please see my comments inline):
Another bug in the implementation of ExtractRecipientTable which I have not been able to identify the cause yet is that it is unable to read correctly the RecipientType for both Cc and Bcc. I've also noticed that there are Null property values, this might have something to do with it... I'm still investigating.
Related to this bug is also another bug where prop.ReadNextRow () is unable to retrieve the actual following row in the recipient table. One fix which I discovered to work is to break out of the while loop immediately after the MailboxAddress is created:
It seems like there is an issue of calling prop.ReadNextProperty() to process the rest of the remaining properties in the row...
Another issue which I noticed was after this function is called, the AttributeTag get's corrupted. In the case of the function ExtractTnefMessage. Please see my commends in-line.
Platform (please complete the following information):
The text was updated successfully, but these errors were encountered: