none
Appointment Categories RRS feed

  • Question

  • Hello,

    I have an application wich copies appointments from one "reference" calendar (source) to other calendars. It uses the EWS API. Actualy it compares if there are allready copied appointments from the reference calendar of the target calendars, if yes it deletes them and copies everything again. This application is running daily for once.

    Everything is working fine.

    My problem is, that some users are giving some oftheir copied appointments a category over their Outlook and after the delet-copy application the categories are gone.

    So what I am trying to do ist, to query the category of the appointment, delete the appointment and the reassing the catergory on that same appointment.

    I have an user for impersonation and he is copying all the appointments from the reference calender to all the users (their calenders), who are in a defined ditribution group.

    To query the appointment Ids I use the DDay.iCal class library.

    Here is my code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using Microsoft.Exchange.WebServices.Data;
    using DDay.iCal;
    using DDay.iCal.Serialization.iCalendar;
    
    namespace TEST
    {
        class Program
        {
            static void Main(string[] args)
            {
                //Instantiate the ExchangeService class+ Exchange Certificate Validation + Imparsonate
                ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
                ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
                service.Credentials = new NetworkCredential("kalenderuser", "*******");
                service.AutodiscoverUrl("kalenderuser@domain.com", RedirectionUrlValidationCallback);
    
                //Determine reference User Calendar
                FolderId SourceCalendarId = new FolderId(WellKnownFolderName.Calendar, "referenzuser@domain.com");
                CalendarFolder SourceCalendar = CalendarFolder.Bind(service, SourceCalendarId);
    
                //Distinguish Distribution Group
                string distributiongroup = "testverteiler@domain.com";
    
                //Determin Date to schearch
                DateTime startDate = DateTime.Now.AddDays(0);
                DateTime endDate = DateTime.Now.AddDays(6);
                CalendarView calView = new CalendarView(startDate, endDate);
    
                //Expand the Menbers from Distributiongroup
                ExpandGroupResults distGroupMembers = service.ExpandGroup(distributiongroup);
    
                //Create an Array for the caching of every Mailbox Calendar Folder
                int i = 0;
                CalendarFolder[] all_distCalender = new CalendarFolder[distGroupMembers.Members.Count()];
    
                foreach (EmailAddress address in distGroupMembers.Members)
                {
                    //Create Calendar Folder IDs for every Mailbox
                    FolderId distUserCalendarId = new FolderId(WellKnownFolderName.Calendar, address.Address);
                    CalendarFolder distCalendar = CalendarFolder.Bind(service, distUserCalendarId);
                    
                    //Add the Folders in Array
                    all_distCalender[i] = distCalendar;
                    i++;
                }
    
                //Find all Appointments form reference Mailbox and copy them in Distributiongroup Members
                FindItemsResults<Appointment> termine = SourceCalendar.FindAppointments(calView);
    
                foreach (Appointment referenceTermine in termine)
                {
                    foreach (CalendarFolder distributionCalendar in all_distCalender)
                    {
                        FindItemsResults<Appointment> distCalendarTermine = distributionCalendar.FindAppointments(calView);
                        foreach (Appointment date in distCalendarTermine)
                        {
                            var Kategorie = date.Categories;
    
                            if (referenceTermine.ICalUid == date.ICalUid)
                            {
                                date.Delete(DeleteMode.HardDelete);
                            }
                        }
                        referenceTermine.Copy(distributionCalendar.Id); 
                    }
                }
            }
            public static bool RedirectionUrlValidationCallback(string redirectionUrl)
            {
                // The default for the validation callback is to reject the URL.
                bool result = false;
    
                Uri redirectionUri = new Uri(redirectionUrl);
    
                // Validate the contents of the redirection URL. In this simple validation
                // callback, the redirection URL is considered valid if it is using HTTPS
                // to encrypt the authentication credentials. 
                if (redirectionUri.Scheme == "https")
                {
                    result = true;
                }
                return result;
            }
    
            public static bool CertificateValidationCallBack(
            object sender,
            System.Security.Cryptography.X509Certificates.X509Certificate certificate,
            System.Security.Cryptography.X509Certificates.X509Chain chain,
            System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                // If the certificate is a valid, signed certificate, return true.
                if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
                {
                    return true;
                }
    
                // If there are errors in the certificate chain, look at each error to determine the cause.
                if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
                {
                    if (chain != null && chain.ChainStatus != null)
                    {
                        foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
                        {
                            if ((certificate.Subject == certificate.Issuer) &&
                               (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                            {
                                // Self-signed certificates with an untrusted root are valid. 
                                continue;
                            }
                            else
                            {
                                if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                                {
                                    // If there are any other errors in the certificate chain, the certificate is invalid,
                                    // so the method returns false.
                                    return false;
                                }
                            }
                        }
                    }
    
                    // When processing reaches this line, the only errors in the certificate chain are 
                    // untrusted root errors for self-signed certificates. These certificates are valid
                    // for default Exchange server installations, so return true.
                    return true;
                }
                else
                {
                    // In all other cases, return false.
                    return false;
                }
            }
        }
    }

    Have you any idea how can I achieve this?

    Thank you

    Ioannis

    Monday, May 9, 2016 10:54 AM

All replies

  • So the Categories property is just a String Array so just save the value before you delete the appointment and then copy it back to the Appointment you copy in and the use the Update Method to update the appointment. You won't get the Id of new item after you copy it so you need write code to find the Items you just copied into the Mailbox and then update them appropriately. You just need to write separate logic for each step.

    Cheers
    Glen

    Tuesday, May 10, 2016 1:21 AM
  • Hello Glen,

    thank you for your answer.

    My Problem is that I can't manage to save the value of appointment.categories and I am not able to query if an appointment has one.

    I don't realy get this appointment.categories property.

    I have tried both option (see below) for testing with no success...

                            if (referenceTermine.ICalUid == date.ICalUid && date.Categories==null)
                            {
                                Console.WriteLine("NULL Subject :" + date.Subject + "    Category: " + date.Categories);
                                
                            }
    
                            if (referenceTermine.ICalUid == date.ICalUid && date.Categories!=null)
                            {
                                Console.WriteLine("EXISTS Subject :" + date.Subject + "    Category: " + date.Categories);
                            }
    

    Has anyone an Idea what I am missin here?

    Cheers

    Ioannis

    Tuesday, May 10, 2016 8:10 AM
  • OK I have finaly maged to filter if a Category exists:

     if (referenceTermine.ICalUid == date.ICalUid && date.Categories.Count > 0)

    Now my problem is to save the value of the category and reapply this category after the appointmet is deleted and copied from the reference calendar.



                foreach (Appointment referenceTermine in termine)
                {
                    foreach (CalendarFolder distributionCalendar in all_distCalender)
                    {
                        FindItemsResults<Appointment> distCalendarTermine = distributionCalendar.FindAppointments(calView);
                        foreach (Appointment date in distCalendarTermine)
                        {
                            if (referenceTermine.ICalUid == date.ICalUid)
                            {
                                date.Delete(DeleteMode.HardDelete);
                            }
                        }
                        referenceTermine.Copy(distributionCalendar.Id); 
                    }
                }

    Tuesday, May 10, 2016 12:21 PM
  • FindAppointments (or FindItems) doesn't return the categories property values  you need to make a separate GetItem (Load or Loadpropertiesforitems) see https://blogs.msdn.microsoft.com/exchangedev/2010/03/16/loading-properties-for-multiple-items-with-one-call-to-exchange-web-services/

    Cheers
    Glen

    Wednesday, May 11, 2016 5:47 AM