InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Searching a meeting with a specific UID using Exchange Web Services 2007

For most items, the item id (which is based on the MAPI entry id) is a good candidate for a long-term identifier. As long as the item is not moved between folders, it remains stable. At least for most items. This is, however, not true for meetings. Exchange recreates meeting items under certain circumstances and the meeting items loose their original entry id, thus the item id is also modified. But a meeting has a different property which uniquely identifies it, even across mailbox boundaries: The UID property. This property is available as a first-class property since Exchange 2007 Service Pack 1. It is a string that looks like this:

   1: 040000008200E00074C5B7101A82E008000000007069352667BBC9010000000000000000100000000C74ABD802575A41BC09B0E12352657B

Since this property is not an Item Id, the GetItem operation cannot be used to bind to a meeting element directly. Sadly, the FindItem operation doesn’t work either, because the Exchange WebServices do not accept a restriction that is based on the UID property.

Luckily, the UID can be read and searched via a MAPI property: The GlobalObjectId. This is a binary property and when fetched looks like this:

   1: BAAAAIIA4AB0xbcQGoLgCAAAAABwaTUmZ7vJAQAAAAAAAAAAEAAAAAx0q9gCV1pBvAmw4SNSZXs=

The value is the equivalent to the UID displayed above, but in a different format. The UID is formatted as a hex-string and the GlobalObjectId is displayes as a Base64 string. Using the following small function, the first representation can be converted into the latter:

   1: private static string GetObjectIdStringFromUid(string id)
   2: {
   3:     var buffer = new byte[id.Length/2];
   4:     for (int i = 0; i < id.Length/2; i++)
   5:     {
   6:         var hexValue = byte.Parse(id.Substring(i*2, 2), NumberStyles.AllowHexSpecifier);
   7:         buffer[i] = hexValue;
   8:     }
   9:     return Convert.ToBase64String(buffer);
  10: }

The value returned from the GetObjectIdStringFromUid can now be used to execute a FindItem operation, specifying a restriction on the GlobalObjectId property. Here is the whole function:

   1: static void Main(string[] args)
   2: {
   3:     ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
   4:  
   5:     const string id = "040000008200E00074C5B7101A82E008000000007069352667BBC9010000000000000000100000000C74ABD802575A41BC09B0E12352657B";
   6:  
   7:     string bufferString = GetObjectIdStringFromUid(id);
   8:  
   9:     var service = new ExchangeServiceBinding
  10:         {
  11:           Url = "https://w2k3x64/ews/exchange.asmx",
  12:           Credentials = new NetworkCredential("bob", "Password!", "contoso"),
  13:           RequestServerVersionValue = new RequestServerVersion { Version = ExchangeVersionType.Exchange2007_SP1}
  14:         };
  15:  
  16:     var response = service.FindItem(new FindItemType
  17:         {
  18:             ParentFolderIds = new[] { new DistinguishedFolderIdType { Id = DistinguishedFolderIdNameType.calendar } },
  19:             ItemShape = new ItemResponseShapeType
  20:                 {
  21:                     BaseShape = DefaultShapeNamesType.AllProperties,
  22:                 },
  23:             Restriction = new RestrictionType {
  24:                 Item = new IsEqualToType
  25:                     {
  26:                       Item = new PathToExtendedFieldType
  27:                         {
  28:                            DistinguishedPropertySetId = DistinguishedPropertySetType.Meeting,
  29:                            DistinguishedPropertySetIdSpecified = true,
  30:                            PropertyId = 0x03,
  31:                            PropertyIdSpecified = true,
  32:                            PropertyType = MapiPropertyTypeType.Binary
  33:                         },
  34:                       FieldURIOrConstant = new FieldURIOrConstantType
  35:                         {
  36:                           Item = new ConstantValueType
  37:                           {
  38:                               Value = bufferString
  39:                           }
  40:                         }
  41:                     }
  42:                 }
  43:         });
  44:     var messageType = ((FindItemResponseMessageType) response.ResponseMessages.Items[0]);
  45:     Console.Out.WriteLine("messageType.ResponseClass = {0}", messageType.ResponseClass);
  46:  
  47:     if (messageType.ResponseClass != ResponseClassType.Success)
  48:     {
  49:         Console.Out.WriteLine(messageType.MessageText);
  50:         return;
  51:     }
  52:     var returnedItems = messageType.RootFolder.Item as ArrayOfRealItemsType;
  53:  
  54:     if (returnedItems == null || returnedItems.Items == null)
  55:     {
  56:         Console.Out.WriteLine("Nothing found.");
  57:         return;
  58:     }
  59:  
  60:     foreach (CalendarItemType item in returnedItems.Items)
  61:     {
  62:         Console.Out.WriteLine("item.Subject = {0}", item.Subject);
  63:         Console.Out.WriteLine("item.UID = {0}", item.UID);
  64:     }
  65:     Console.ReadLine();
  66: }

Posted by Henning Krause on Monday, April 13, 2009 11:45 PM, last modified on Sunday, May 08, 2011 8:37 AM
Permalink | Post RSSRSS comment feed

Comments (9) -

On 4/27/2009 9:25:11 AM dani Indonesia wrote:

dani

thank you so much for your article..very useful for me..
but i&amp;amp;#39;ve got one question, how to apply date based restriction?
i want to get all meeting that start tomorrow..
thanks again..

Reply

On 6/9/2009 9:37:26 PM Dave United States wrote:

Dave

I tried this example, but I get a server exception. Here is my soap envelope. Do you see what is wrong? The uid was:
040000008200E00074C5B7101A82E00800000000600BAAAC15E9C9010000000000000000100000009E5FDB1DD9AE774B90094A64786E0896 and was Base64&amp;amp;#39;ed.
Thanks,
Dave

&amp;amp;amp;lt;?xml version=&amp;amp;#39;1.0&amp;amp;#39; encoding=&amp;amp;#39;UTF-8&amp;amp;#39;?&amp;amp;amp;gt;&amp;amp;amp;lt;S:Envelope xmlns:S=&amp;amp;amp;quot;schemas.xmlsoap.org/.../&amp;amp;amp;quot;&amp;amp;amp;gt;
&amp;amp;amp;lt;S:Header&amp;amp;amp;gt;&amp;amp;amp;lt;ns2:MailboxCulture xmlns=&amp;amp;amp;quot;schemas.microsoft.com/.../messages&amp;amp;amp;quot; xmlns:ns2=&amp;amp;amp;quot;schemas.microsoft.com/.../ns2:MailboxCulture&amp;amp;amp;gt;
&amp;amp;amp;lt;ns2:RequestServerVersion xmlns=&amp;amp;amp;quot;schemas.microsoft.com/.../messages&amp;amp;amp;quot; xmlns:ns2=&amp;amp;amp;quot;schemas.microsoft.com/.../types&amp;amp;amp;quot; Version=&amp;amp;amp;quot;Exchange2007_SP1&amp;amp;amp;quot;/&amp;amp;amp;gt;
&amp;amp;amp;lt;/S:Header&amp;amp;amp;gt;
&amp;amp;amp;lt;S:Body&amp;amp;amp;gt;
&amp;amp;amp;lt;FindItem xmlns=&amp;amp;amp;quot;schemas.microsoft.com/.../messages&amp;amp;amp;quot; xmlns:ns2=&amp;amp;amp;quot;schemas.microsoft.com/.../types&amp;amp;amp;quot; Traversal=&amp;amp;amp;quot;Shallow&amp;amp;amp;quot;&amp;amp;amp;gt;
&amp;amp;amp;lt;ItemShape&amp;amp;amp;gt;
&amp;amp;amp;lt;ns2:BaseShape&amp;amp;amp;gt;AllProperties&amp;amp;amp;lt;/ns2:BaseShape&amp;amp;amp;gt;
&amp;amp;amp;lt;/ItemShape&amp;amp;amp;gt;
&amp;amp;amp;lt;Restriction&amp;amp;amp;gt;
&amp;amp;amp;lt;ns2:IsEqualTo&amp;amp;amp;gt;
&amp;amp;amp;lt;ns2Tongath xmlns:xsi=&amp;amp;amp;quot;www.w3.org/.../XMLSchema-instance&amp;amp;amp;quot; xsi:type=&amp;amp;amp;quot;ns2TongathToExtendedFieldType&amp;amp;amp;quot; PropertyType=&amp;amp;amp;quot;Binary&amp;amp;amp;quot; PropertyId=&amp;amp;amp;quot;3&amp;amp;amp;quot; DistinguishedPropertySetId=&amp;amp;amp;quot;Meeting&amp;amp;amp;quot;/&amp;amp;amp;gt;
&amp;amp;amp;lt;ns2:FieldURIOrConstant&amp;amp;amp;gt;
&amp;amp;amp;lt;ns2:Constant Value=&amp;amp;amp;quot;MDQwMDAwMDA4MjAwRTAwMDc0QzVCNzEwMUE4MkUwMDgwMDAwMDAwMDYwMEJBQUFDMTVFOUM5MDEwMDAwMDAwMDAwMDAwMDAwMTAwMDAwMDA5RTVGREIxREQ5QUU3NzRCOTAwOTRBNjQ3ODZFMDg5Ng==&amp;amp;amp;quot;/&amp;amp;amp;gt;
&amp;amp;amp;lt;/ns2:FieldURIOrConstant&amp;amp;amp;gt;
&amp;amp;amp;lt;/ns2:IsEqualTo&amp;amp;amp;gt;
&amp;amp;amp;lt;/Restriction&amp;amp;amp;gt;
&amp;amp;amp;lt;ParentFolderIds&amp;amp;amp;gt;
&amp;amp;amp;lt;ns2LaughingistinguishedFolderId Id=&amp;amp;amp;quot;calendar&amp;amp;amp;quot;/&amp;amp;amp;gt;
&amp;amp;amp;lt;/ParentFolderIds&amp;amp;amp;gt;
&amp;amp;amp;lt;/FindItem&amp;amp;amp;gt;
&amp;amp;amp;lt;/S:Body&amp;amp;amp;gt;
&amp;amp;amp;lt;/S:Envelope&amp;amp;amp;gt;

Reply

On 6/19/2009 9:02:06 PM Dave United States wrote:

Dave

Here is how to do this in java using JAX-WS.

  public RestrictionType getEventUidRestriction(String uid) {
    try  {
      String enc = getObjectIdStringFromUid(uid);

      RestrictionType rt = new RestrictionType();

      PathToExtendedFieldType peft = new PathToExtendedFieldType();
      peft.setDistinguishedPropertySetId(DistinguishedPropertySetType.MEETING);
      peft.setPropertyType(MapiPropertyTypeType.BINARY);
      peft.setPropertyId(0x03);

      FieldURIOrConstantType cons = new FieldURIOrConstantType();
      ConstantValueType ty = new ConstantValueType();
      ty.setValue(enc);
      cons.setConstant(ty);

      JAXBElement&amp;amp;amp;lt;PathToExtendedFieldType&amp;amp;amp;gt; element =
        new JAXBElement&amp;amp;amp;lt;PathToExtendedFieldType&amp;amp;amp;gt;(new QName(&amp;amp;amp;quot;schemas.microsoft.com/.../types&amp;amp;amp;quot;,
                                                            &amp;amp;amp;quot;ExtendedFieldURI&amp;amp;amp;quot;),
                                                  PathToExtendedFieldType.class,
                                                  peft);

      IsEqualToType et = new IsEqualToType();
      et.setPath(element);
      et.setFieldURIOrConstant(cons);

      TwoOperandExpressionType request = et;
      rt.setSearchExpression(new JAXBElement&amp;amp;amp;lt;TwoOperandExpressionType&amp;amp;amp;gt;(new QName(&amp;amp;amp;quot;schemas.microsoft.com/.../types&amp;amp;amp;quot;,
                                                                                 &amp;amp;amp;quot;IsEqualTo&amp;amp;amp;quot;),
                                                                       TwoOperandExpressionType.class,
                                                                       request));
      return rt;
    } catch (Exception e)  {
      throw new RuntimeException(e);
    }
  }

  private String getObjectIdStringFromUid(String uid) {
    String retStr = null;
    byte[ ] buffer = new byte[uid.length()/2];
    for (int i=0; i&amp;amp;amp;lt;uid.length()/2; i++) {
      String sub = uid.substring(i*2, i*2+2);
      buffer[i] = (byte) Integer.parseInt(sub, 16);
    }
    Base64 b = new Base64();
    retStr = new String(b.encodeBase64(buffer));
    return retStr;
  }

Reply

On 7/22/2009 2:13:32 PM Thilo Langbein Germany wrote:

Thilo Langbein

I want to read the color/category of a meeting/calendar-item. Ist this in an extended property or where?
Can someone help?

&amp;amp;amp;gt;Thilo

Reply

On 12/10/2010 10:51:24 AM Shalini United States wrote:

Shalini

Here is the SOAP Request&amp;amp;#39;s Body:

&amp;amp;amp;lt;FindItem xmlns=&amp;amp;amp;quot;schemas.microsoft.com/.../messages&amp;amp;amp;quot;   xmlns:t=&amp;amp;amp;quot;schemas.microsoft.com/.../types&amp;amp;amp;quot;   Traversal=&amp;amp;amp;quot;Shallow&amp;amp;amp;quot;&amp;amp;amp;gt;
&amp;amp;amp;lt;ItemShape&amp;amp;amp;gt;
&amp;amp;amp;lt;t:BaseShape&amp;amp;amp;gt;AllProperties&amp;amp;amp;lt;/t:BaseShape&amp;amp;amp;gt;
&amp;amp;amp;lt;/ItemShape&amp;amp;amp;gt;
&amp;amp;amp;lt;Restriction&amp;amp;amp;gt;
&amp;amp;amp;lt;t:IsEqualTo&amp;amp;amp;gt;
&amp;amp;amp;lt;t:ExtendedFieldURI PropertySetId=&amp;amp;amp;quot;6ED8DA90-450B-101B-98DA-00AA003F1305&amp;amp;amp;quot;
PropertyId=&amp;amp;amp;quot;3&amp;amp;amp;quot; PropertyType=&amp;amp;amp;quot;Binary&amp;amp;amp;quot; /&amp;amp;amp;gt;
&amp;amp;amp;lt;t:FieldURIOrConstant&amp;amp;amp;gt;
&amp;amp;amp;lt;t:Constant Value=&amp;amp;amp;quot;BAAAAII7YJXIl1MJ8=&amp;amp;amp;quot;/&amp;amp;amp;gt;  /* GUID */
&amp;amp;amp;lt;/t:FieldURIOrConstant&amp;amp;amp;gt;
&amp;amp;amp;lt;/t:IsEqualTo&amp;amp;amp;gt;
&amp;amp;amp;lt;/Restriction&amp;amp;amp;gt;
&amp;amp;amp;lt;ParentFolderIds&amp;amp;amp;gt;
&amp;amp;amp;lt;tLaughingistinguishedFolderId Id=&amp;amp;amp;quot;calendar&amp;amp;amp;quot;/&amp;amp;amp;gt;
&amp;amp;amp;lt;/ParentFolderIds&amp;amp;amp;gt;
&amp;amp;amp;lt;/FindItem&amp;amp;amp;gt;

Reply

On 5/6/2011 12:06:32 PM HP United States wrote:

HP

Thanks for the post! I am able to get calendar item using the function. However, it fails to retrieve calendar item of Recurring meeting is there a way to get those meetings as well?

I searched for to resolve the issue and found that, for recurring meeting it requires to pass CleanGlobalObjectId. I only have a GlobalObjectId, can I get a CleanGlobalObjectId from GlobalObjectId and then retrieve the meeting?

Reply

On 5/8/2011 8:37:13 AM HP United States wrote:

HP

I am unable to get recurring calendar item, by passing GlobalObject Id of it in the restriction. I have also tried to compare the GlobalObjectId value to CleanGlobalObjectId MAPI property, it still doesn&amp;amp;#39;t fetch recurring calendar item. Can please let me know how to get Recurring meetings from GlobalbjectId?

Reply

On 12/22/2011 9:23:28 AM Josep wrote:

Josep

Hi,
i found this post very useful, but I would like to implement the same using the EWS API functions.

In my case I am using the ExchangeService object instead of the ExchangeServiceBinding and there is no FindItem function and I don&amp;amp;amp;#39;t know how to use the FindItems that is provided in the ExchangeService object.

I need some help.

Thanks

Reply

On 7/9/2012 3:23:01 PM Merken wrote:

Merken

Thank you for this snippet, it&amp;#39;s a life saver !!!

Cheers

Reply

 +Pingbacks and trackbacks (2)

Add comment

biuquote
  • Comment
  • Preview
Loading