Sicos1977 / MsgKit

A .NET library to make MSG files without the need for Outlook
206 stars 56 forks source link

String Named Property #133

Open mdmdelmotte opened 3 months ago

mdmdelmotte commented 3 months ago

Hello, Am i wrong or MsgKit handle only numerical named property and not string named ? If we take the property used by AIP (Azure Information protection) it does not have an numerical ID, it's a string ID called msip_labels. If we add this property in NamedPropertyTags.cs like new NamedPropertyTag(0x0000,"msip_labels",new guid ("00020386....",PropertyType.PT_UNICODE) it will not work. I see also in the code that we have no special logic for Kind==1. According to me the code handles only numerical ID.

Do you confirm ?

Sicos1977 commented 3 months ago

It will handle named and unnamed properties

You need this method for named properties

    #region AddNamedProperty
    /// <summary>
    ///     Adds a custom named property to the message or replaces it when it already exists
    /// </summary>
    /// <param name="namedProperty"><see cref="NamedPropertyTag"/></param>
    /// <param name="value">The value of the property</param>
    /// <exception cref="MKMessageSaved">Raised when the message has already been saved with the Save method</exception>
    public void AddProperty(NamedPropertyTag namedProperty, object value)
    {
        if (_saved)
            throw new MKMessageSaved("The message can't be modified when it already has been saved");

        NamedProperties.AddProperty(namedProperty, value);
    }
    #endregion
Sicos1977 commented 3 months ago

Named properties only get an ID in the 0x8000 range when they are put inside the MSG file. These id's are generated when the property is put into the MSG file

mdmdelmotte commented 3 months ago

Hello Sicos, Thanks for the answer, but i think we are not talking about the same. Both are named properties, numerical and string based . Page 7/38 in the OXMSG SPEC.

For example, in the spec we see that it's handled differently but the code in msgkit never refer to the second equation :

For numerical named properties, the following equation is used:
Stream ID = 0x1000 + ((ID XOR (GUID index << 1))) MOD 0x1F
For string named properties, the following equation is used:
Stream ID = 0x1000 + ((ID XOR (GUID index << 1 |1))) MOD 0x1F

For me the call you are refering to is targeting a property kind=Lid and not Name. ==>

internal void AddProperty(NamedPropertyTag mapiTag, object obj)
    {
        // Named property field 0000. 0x8000 + property offset
        _topLevelProperties.AddProperty(new PropertyTags.PropertyTag((ushort)(0x8000 + _namedPropertyIndex++), mapiTag.Type), obj);

        Add(new NamedProperty
        {
            NameIdentifier = mapiTag.Id,
            Guid = mapiTag.Guid,
            Kind = PropertyKind.Lid
        });
    }

==> Kind = PropertyKind.Lid

mdmdelmotte commented 3 months ago

Named properties only get an ID in the 0x8000 range when they are put inside the MSG file. These id's are generated when the property is put into the MSG file

i do agree with that. With an offset after 0x8000. But For me when you specify a PropertyName and a PropertyID=0x0000 , the name will never be used when written to the stream. Cause if you add a new Named PropertyTag like you did for the PidLiBilling it will not work. I scan the generated MailMessage with Outlook spy and see that the property is not there. If i generate the property with a string based name and not an integer, via outlook spy, the property is well saved in the mailMessage, and the AIP flag is well present in the mail. All this because the property is seen as Kind=1 (string id) and not Kind=0.

Sicos1977 commented 3 months ago

I need to look into this, I don't know if I ever did something with both kind types.

Sicos1977 commented 3 months ago

This is how I read it:

For numerical named properties, the following equation is used: Stream ID = 0x1000 + ((ID XOR (GUID index << 1))) MOD 0x1F

This are the old properties below the 0x8000 range

For string named properties, the following equation is used: Stream ID = 0x1000 + ((ID XOR (GUID index << 1 |1))) MOD 0x1F

This are the named properties in the 0x8000 range

But I can be wrong because it is a long time ago when I build this. It would be nice to have an example MSG file so that I can look into it with Outlook Spy. It is probably also better so that we understand each other and don't think that we are talking about the same but mean something else :-)

mdmdelmotte commented 3 months ago

Hello Sicos,

Thanks again for your time and answers above. You can find here the screenshot where we see the string named properties and another one when i use a random one present in your propertiesTag file with ID 0x822E. You will find the raw .msg files as well that can be opened with OutlookSpy.

What you are refering to here above about old and new properties, i m well aware, it's tagged properties before 0x8000 and the named properties above 0x8000. Here i am well talking about named with as you say an incremental ID, but a property with Kind=mnid_string. It's the section 3.2.1.1.2 in the OXMSG spec.

For your info, the goal is to be able to use the outlook AIP plugin on emails, showing the sensitivity label (Public,Private,Secret,...), so when i generated a .msg with MsgKit i would like to add the property. I m surprised that nobody tried to do it with MsgKit before :-)

i would like to help you to enhance the library with this functionality about string name properties, but i have to admit that i am a little bit lost in the logic with the streams and the mapping properties. :-)

Do not hesitate to contact me if we have to dig into it together :-)

Kind Regards.

Capture_WithNumericalID Capture Example msgs.zip

Sicos1977 commented 3 months ago

I have to do some reading about how all this works, it already took me an awful lot of reading to even understand how the MSG format works and translate that to a C# library that can be used by other software programmers. The documentation is good but the problem is understanding what somebody means in the documentation. It was a lot of trial and error before I got a working library.

And I was the first one doing it in C# open source so I had no other places where I could "borrow" some code...

mdmdelmotte commented 3 months ago

I have to do some reading about how all this works, it already took me an awful lot of reading to even understand how the MSG format works and translate that to a C# library that can be used by other software programmers. The documentation is good but the problem is understanding what somebody means in the documentation. It was a lot of trial and error before I got a working library.

And I was the first one doing it in C# open source so I had no other places where I could "borrow" some code...

I totally understand and the work you did is awesome. It works very good, thanks for the community. This microsoft spec document is really painfull to read ^^

Sicos1977 commented 3 months ago

I'll try to look into it further this weekend... during the week I also have my day job that also involves in a lot of programming