9

I've got the following code:

    private void ListCalendarFolders(ref List<EBCalendar> items, int offset)
    {
        var pageSize = 100;
        var view = new FolderView(pageSize, offset, OffsetBasePoint.Beginning);
        view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
        view.PropertySet.Add(FolderSchema.DisplayName);
        view.PropertySet.Add(FolderSchema.EffectiveRights);

        view.Traversal = FolderTraversal.Deep;

        FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.MsgFolderRoot, view);
        foreach (Folder myFolder in findFolderResults.Folders)
        {
            if (myFolder is CalendarFolder)
            {
                var folder = myFolder as CalendarFolder;
                items.Add(EBCalendar.FromEWSFolder(folder));
            }
        }

        if (findFolderResults.MoreAvailable)
        {
            offset = offset + pageSize;
            ListCalendarFolders(ref items, offset);
        }
    }

Where service is an ExchangeService instance. Unfortunately, it still lists folders that have been deleted, and it doesn't list shared calendars.

How can I get it to list all the shared calendars, and how can I get it to not include the folders that have been deleted?

synic
  • 26,359
  • 20
  • 111
  • 149

3 Answers3

16

By Shared Calendars do you mean the calendars under the other calendars node in Outlook ?

Other Calendars Node

If so these Items are NavLinks that are stored in the Common Views folder in a Mailbox which is under the NonIPMSubtree (root) see http://msdn.microsoft.com/en-us/library/ee157359(v=exchg.80).aspx. You can use EWS to get the NavLinks from a Mailbox and use the PidTagWlinkAddressBookEID extended property to get the X500 address of the Mailbox these Links refer to and then use Resolve Name to resolve that to a SMTP Address. Then all you need to do is Bind to that folder eg

     static Dictionary<string, Folder> GetSharedCalendarFolders(ExchangeService service, String mbMailboxname)
    {
        Dictionary<String, Folder> rtList = new System.Collections.Generic.Dictionary<string, Folder>();

        FolderId rfRootFolderid = new FolderId(WellKnownFolderName.Root, mbMailboxname);
        FolderView fvFolderView = new FolderView(1000);
        SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "Common Views");
        FindFoldersResults ffoldres = service.FindFolders(rfRootFolderid, sfSearchFilter, fvFolderView);
        if (ffoldres.Folders.Count == 1)
        {

            PropertySet psPropset = new PropertySet(BasePropertySet.FirstClassProperties);
            ExtendedPropertyDefinition PidTagWlinkAddressBookEID = new ExtendedPropertyDefinition(0x6854, MapiPropertyType.Binary);
            ExtendedPropertyDefinition PidTagWlinkGroupName = new ExtendedPropertyDefinition(0x6851, MapiPropertyType.String);

            psPropset.Add(PidTagWlinkAddressBookEID);
            ItemView iv = new ItemView(1000);
            iv.PropertySet = psPropset;
            iv.Traversal = ItemTraversal.Associated;

            SearchFilter cntSearch = new SearchFilter.IsEqualTo(PidTagWlinkGroupName, "Other Calendars");
            // Can also find this using PidTagWlinkType = wblSharedFolder
            FindItemsResults<Item> fiResults = ffoldres.Folders[0].FindItems(cntSearch, iv);
            foreach (Item itItem in fiResults.Items)
            {
                try
                {
                    object GroupName = null;
                    object WlinkAddressBookEID = null;

                    // This property will only be there in Outlook 2010 and beyond
                    //https://msdn.microsoft.com/en-us/library/ee220131(v=exchg.80).aspx#Appendix_A_30
                    if (itItem.TryGetProperty(PidTagWlinkAddressBookEID, out WlinkAddressBookEID))
                    {

                        byte[] ssStoreID = (byte[])WlinkAddressBookEID;
                        int leLegDnStart = 0;
                        // Can also extract the DN by getting the 28th(or 30th?) byte to the second to last byte 
                        //https://msdn.microsoft.com/en-us/library/ee237564(v=exchg.80).aspx
                        //https://msdn.microsoft.com/en-us/library/hh354838(v=exchg.80).aspx
                        String lnLegDN = "";
                        for (int ssArraynum = (ssStoreID.Length - 2); ssArraynum != 0; ssArraynum--)
                        {
                            if (ssStoreID[ssArraynum] == 0)
                            {
                                leLegDnStart = ssArraynum;
                                lnLegDN = System.Text.ASCIIEncoding.ASCII.GetString(ssStoreID, leLegDnStart + 1, (ssStoreID.Length - (leLegDnStart + 2)));
                                ssArraynum = 1;
                            }
                        }
                        NameResolutionCollection ncCol = service.ResolveName(lnLegDN, ResolveNameSearchLocation.DirectoryOnly, false);
                        if (ncCol.Count > 0)
                        {

                            FolderId SharedCalendarId = new FolderId(WellKnownFolderName.Calendar, ncCol[0].Mailbox.Address);
                            Folder SharedCalendaFolder = Folder.Bind(service, SharedCalendarId);
                            rtList.Add(ncCol[0].Mailbox.Address, SharedCalendaFolder);


                        }

                    }
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception.Message);
                }

            }
        }
        return rtList;
    }

Cheers Glen

Glen Scales
  • 20,495
  • 1
  • 20
  • 23
  • Wow, that's awesome. I'm going to give it a try right now. Thank you! – synic May 21 '14 at 15:03
  • This works great to obtain shared calendar folders. But now I am having trouble when I try to access the items in shared calendars. Basically I need to get the free/busy state. I was calling `service.FindItems(SharedCalendaFolder.Id, iCalenderview)` and I got "Access is denied. Check credentials and try again." error. But in outlook web app I am able to see shared calendar events. – Dimuthu Apr 01 '16 at 13:06
  • To Access a Calendar you will need at least Read Access to the calendar I would say you only have FreeBusy rights at the moment so you can only use the GerUseravailiblity operation in that case unless you assign more rights to the calendar folder for your account. – Glen Scales Apr 01 '16 at 22:40
  • Hi, unfortunately, this doesn't work if the shared calendar is not the default Calendar. E.g. user A created a calendar called Public and shared it with user B. The TryGetProperty fails on these items, even though it works with default calendars. – KirilStankov Aug 09 '19 at 13:13
  • Is there a EWS XML request / response equivalent of this? I'm having the same issue, but not sure how to translate this into XML. – strangetimes Nov 16 '19 at 14:27
1

You need to specify a searchfilter. this is described here, though im not sure which Schema is the correct one, my guess would be Archieved.

So you would do something like this:

SearchFilter searchFilter = new SearchFilter.IsEqualTo(FolderSchema.Archieved, false);

FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.MsgFolderRoot,searchFilter, view);
CSharpie
  • 9,195
  • 4
  • 44
  • 71
  • Thanks! This solves the deleted ones showing. Have any idea about the shared folders not showing up? – synic May 20 '14 at 20:51
  • I bellieve you cant do this by using a folder view, instead you need to define a FolderId with the mailbox that is sharing the folder. – CSharpie May 20 '14 at 20:59
  • But I don't know the folder ID. I'd like a list of all shared/public/owned folders. – synic May 20 '14 at 20:59
  • Ok try with a second FindFolders-Call using WellKnownfolderName.PublicFoldersRoot Maybe the enum supports flags so you might be able to do it in one FindFoldersCall – CSharpie May 20 '14 at 21:02
  • Check this questions first Answer aswell http://stackoverflow.com/questions/13877629/how-to-get-all-items-from-folders-and-sub-folders-of-publicfolders-using-ews-man – CSharpie May 20 '14 at 21:04
  • I don't seem to have access to the FolderSchema.Archived property. Any ideas? I'm returning all deleted items as well and its not very useful. – Lee Harrison Jan 13 '15 at 17:51
1

Glen post is perfect but binding folder gives error. However i solved this. Instead of this line:

Folder SharedCalendaFolder = Folder.Bind(service, SharedCalendarId);

use the following line for shared folder binding

CalendarFolder calendar = CalendarFolder.Bind(service, new FolderId(WellKnownFolderName.Calendar, OwnerEmailAddress), new PropertySet());

Here OwnerEmailAddress is Email Address of Owner or you can write ncCol[0].Mailbox.Address if using Glen's code.

Sahil Bhatia
  • 165
  • 1
  • 1
  • 8