Re: CDO 1.2.1 Personal Distribution Lists

From: Dmitry Streblechenko \(MVP\) (dmitry_at_dimastr.com)
Date: 08/20/04


Date: Fri, 20 Aug 2004 11:05:24 -0700

Yes, it is union - I simply use it because I use strings as dynamic arrays.
The length (4 bytes DWORD) needs to be concatenated with other data
represented as a string. It will probably be easier to look at an existing
DL using OutlookSpy (click IMessage, select the prop, click the button next
to the Value edit) to make sense of the entry id structure.

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

"Tom Delany" <Tom@compusven.com.nospam> wrote in message
news:pan.2004.08.20.15.40.04.781000@compusven.com.nospam...
> On Fri, 20 Aug 2004 11:24:12 -0400, Tom Delany wrote:
>
> > On Thu, 19 Aug 2004 12:07:35 -0700, Dmitry Streblechenko (MVP) wrote:
> >
> >> Here is how I extract the AB entry IDs from the DL's Members entry ids
(in
> >> Delphi, sorry):
> >>
> >> function DLMemberEntryIDToABEntryID(const Value : string):string;
> >> var ind : integer;
> >> begin
> >> Result:='';
> >> if IsOneOffEID(Value) then begin
> >> //one off entry id
> >> Result:=Value;
> >> end
> >> else if Copy(Value, 5, 16) =
> >> #$C0#$91#$AD#$D3#$51#$9D#$CF#$11#$A4#$A9#$00#$AA#$00#$47#$FA#$A4 then
begin
> >> //this is a fake DL provider UID, it is not registered with the
MAPI
> >> session
> >> //oh boy, now we need to parse it...
> >> ind:=byte(Value[21]); //byte 21
> >> case ind of
> >> $C2, $C3 : Result:=OABEntryIDFromIPMEntryID(Copy(Value, 22,
MaxInt),
> >> #4, #0); //email1
> >> $D3 : Result:=OABEntryIDFromIPMEntryID(Copy(Value, 22,
MaxInt),
> >> #4, #1); //email2
> >> $E3 : Result:=OABEntryIDFromIPMEntryID(Copy(Value, 22,
MaxInt),
> >> #4, #3); //email3
> >> $83 : Result:=OABEntryIDFromIPMEntryID(Copy(Value, 22,
MaxInt),
> >> #4, #4); //business fax
> >> $93 : Result:=OABEntryIDFromIPMEntryID(Copy(Value, 22,
MaxInt),
> >> #4, #5); //home fax
> >> $A3 : Result:=OABEntryIDFromIPMEntryID(Copy(Value, 22,
MaxInt),
> >> #4, #6); //other fax
> >> $B4 : Result:=OABEntryIDFromIPMEntryID(Copy(Value, 22,
MaxInt),
> >> #5, #$FF); //OAB DL
> >> $B5, $B6 : Result:=Copy(Value, 22, MaxInt); //external entry
(GAL,
> >> GAL DL, etc)
> >> end;
> >> end;
> >> end;
> >>
> >> function OABEntryIDFromIPMEntryID(IPMEntryID : string; Type_, Index :
> >> char):string;
> >> type TLenRec = packed record
> >> case integer of
> >> 0 : (Len : ULONG);
> >> 1 : (Str : array[0..3] of char);
> >> end;
> >> var LenRec : TLenRec;
> >> begin
> >> LenRec.Len:=Length(IPMEntryID);
> >>
> >>
Result:=#$00#$00#$00#$00#$FE#$42#$AA#$0A#$18#$C7#$1A#$10#$E8#$85#$0B#$65#$1C
> >> #$24#$00#$00+ //flags + MUID
> >> #$03#$00#$00#$00+
> >> //What is it?
> >> Type_+#$00#$00#$00+
> >> //4 for IPM.Contact, 5 for IPM.DistList
> >> Index+#$00#$00#$00+
> >> //index - email1, email2, fax1, ect
> >> LenRec.Str[0]+LenRec.Str[1]+LenRec.Str[2]+LenRec.Str[3]+
> >> //Length
> >> IPMEntryID+
> >> //Message entry id
> >> #$00#$00#$00;
> >> end;
> >>
> >>
> >> Dmitry Streblechenko (MVP)
> >> http://www.dimastr.com/
> >> OutlookSpy - Outlook, CDO
> >> and MAPI Developer Tool
> >>
> >>
> >> "Tom Delany" <Tom@compusven.com.nospam> wrote in message
> >> news:pan.2004.08.19.17.41.49.656000@compusven.com.nospam...
> >>> On Thu, 19 Aug 2004 10:11:50 -0400, Tom Delany wrote:
> >>>
> >>> > Dmitry,
> >>> >
> >>> > I am sorry, but I do not completely follow you about the Members
> >> property.
> >>> > Are you saying that it is doubly wrapped? I don't follow the part
about
> >>> > it wrapping the Address Book entry ID, which in turn wraps the
> >>> > IPM.DistList message. Can you give me a simplified example? I am
> >> trying
> >>> > to look at some existing D/Ls here to figure out what you mean, but
I
> >> must
> >>> > be dense.
> >>> >
> >>> > Even when I finally understand what you mean, I don't have much hope
of
> >>> > recreating this programtically, since I have no idea what to wrap
the
> >>> > entry IDs with to make Outlook happy.
> >>> >
> >>> > Thanks for the help, as always.
> >>> >
> >>> > Cheers,
> >>> >
> >>> > Tom Delany
> >>> >
> >>> > On Wed, 18 Aug 2004 13:43:39 -0700, Dmitry Streblechenko (MVP)
wrote:
> >>> >
> >>> >> For the Members prop, Outlook creates a fake entry id that wraps
the AB
> >>> >> entry id inside of it. That entry id in turn also wraps the entry
id of
> >> the
> >>> >> corresponding IPM.DistList message.
> >>> >> For OneOffMembers, Outlook creates an invalid one-off entry id with
the
> >>> >> display name, e-mail type of "MAPIPDL" and Address = "Unknown"
> >>> >>
> >>> >> Dmitry Streblechenko (MVP)
> >>> >> http://www.dimastr.com/
> >>> >> OutlookSpy - Outlook, CDO
> >>> >> and MAPI Developer Tool
> >>> >>
> >>> >>
> >>> >> "Tom Delany" <Tom@compusven.com.nospam> wrote in message
> >>> >> news:pan.2004.08.18.19.00.33.937000@compusven.com.nospam...
> >>> >>> Dmitry et al,
> >>> >>>
> >>> >>> Another question about distribution list members. When a
> >>> >>> distribution list that appears in a mailbox's "Contacts"
> >>> >>> folder is added as a member of another distribution list
> >>> >>> (also in the "Contacts" folder), what is the entry ID that
> >>> >>> is populated in the Members or OneOffMembers properties?
> >>> >>> It does not appear to be the entry ID for the D/L itself,
> >>> >>> and typically, personal D/Ls do not have SMTP addresses.
> >>> >>>
> >>> >>> I am trying to add a D/L as a member to another D/L, and am
> >>> >>> having a devil of a time with it. I have sucessfully
> >>> >>> populated regular contact addresses into the D/L by putting
> >>> >>> the entry ID of the address into the array, but cannot
> >>> >>> figure out what to use for other D/Ls that are members.
> >>> >>>
> >>> >>> Thanks,
> >>> >>>
> >>> >>> Tom Delany
> >>> >>>
> >>>
> >>> OK. I am finally starting to get it. I finally decided to dump the
D/L
> >>> properties to a file using Outlook Spy (why did I not try that
sooner?),
> >>> and it started making sense to me. The Members property in my example
> >>> appears to contain the Entry ID of the contact or D/L that is a member
of
> >>> this D/L, preceded by some type of 21 byte "prefix" for lack of a
better
> >>> word. The prefixes for the contacts that are members all appear to be
> >>> identical. The D/L member has a slightly different prefix.
> >>>
> >>> I guess my next question is, "Are these prefixes always the same?"
Can I
> >>> get away with prepending the one version to contacts for D/L members,
and
> >>> the other to D/Ls that are members?
> >>>
> >>> Thanks for your patience and help.
> >>>
> >>> Tom Delany
> >>>
> >>>
> >
> > Dmitry,
> >
> > I am sorry. I don't know Delphi syntax. I think I have figured out the
> > first part of the code snippet, but I am scratching my head over some of
> > the OABEntryIDFromIPMEntryID() function. For example:
> >
> >> type TLenRec = packed record
> >> case integer of
> >> 0 : (Len : ULONG);
> >> 1 : (Str : array[0..3] of char);
> >> end;
> >
> > Looks like you might be defining some type of structure, but I am not
> > sure. Or is it the equivalent of a C/C++ union? Then you are taking
the
> > EntryID that has had the prefix stripped off in the first function, and
> > wrapping different stuff around it?
> >
> > Sorry to keep bugging you.
> >
> > Tom D.
>
> As I keep looking at that code that has me confused, I am convinced
> that it is like a union. You are using it to convert the length to hex
> chars, right?
>
> Do the length chars come out in Big Endian or Little Endian arrangement?
> i.e. If the length was 00010049 hex (way too big. Just using as an
> example.), in Big Endian, the string would come out as: 00 01 00 49, but
> in Little Endian it would be: 49 00 01 00.
>
> Tom D.
>