/// <summary> /// Generates the I calendar. /// </summary> /// <exception cref="System.ArgumentNullException"> /// eventEntity /// or /// inbox /// </exception> private static iCalendar GenerateICalendar(Appointment appointment, string emailAddress) { if (appointment == null) { throw new ArgumentNullException("eventEntity"); } if (string.IsNullOrEmpty(emailAddress)) { throw new ArgumentNullException("emailAddress"); } try { ///// // Calendar object ///// var calendar = new iCalendar( ); var calendarEvent = calendar.Create <iCalEvent>( ); ICalUidContainer iCalUidContainer = appointment.ICalAppt.CalendarId; string uid = null; ///// // If there exists a reference to a previously sent message, obtain it and use the iCal UID from it. // Note* This is required to ensure proposed updates modify the existing calendar entry and no create a new one. ///// if (iCalUidContainer != null) { uid = iCalUidContainer.ICalUid; if (!string.IsNullOrEmpty(uid)) { calendarEvent.Uid = uid; } } ///// // Create the time zone object. ///// TimeZoneInfo tzi = CreateTimezone( ); ITimeZone tz = null; if (tzi != null) { tz = calendar.AddTimeZone(tzi); } ///// // Start time. ///// if (appointment.EventStart != null) { calendarEvent.Start = tz != null ? new iCalDateTime(ConvertDateTime(appointment.EventStart.Value, TimeZoneInfo.Utc, tzi), tz.TzId) : new iCalDateTime(appointment.EventStart.Value); } ///// // End time. ///// if (appointment.EventEnd != null) { calendarEvent.End = tz != null ? new iCalDateTime(ConvertDateTime(appointment.EventEnd.Value, TimeZoneInfo.Utc, tzi), tz.TzId) : new iCalDateTime(appointment.EventEnd.Value); } ///// // All day event. ///// if (appointment.EventIsAllDay != null) { calendarEvent.IsAllDay = appointment.EventIsAllDay.Value; } ///// // Location. ///// if (appointment.EventLocation != null) { calendarEvent.Location = appointment.EventLocation; } ///// // Priority. (CUA defined) ///// if (appointment.EventEmailPriority != null) { EventEmailPriorityEnum eventEmailPriorityStatus = appointment.EventEmailPriority; switch (eventEmailPriorityStatus.Alias) { case "core:lowPriority": calendarEvent.Priority = 9; break; case "core:normalPriority": calendarEvent.Priority = 5; break; case "core:highPriority": calendarEvent.Priority = 1; break; } } ///// // Summary. ///// calendarEvent.Summary = !string.IsNullOrEmpty(appointment.Name) ? string.Format("{0} - {1}", appointment.Name, GlobalStrings.DefaultICalSummary) : GlobalStrings.DefaultICalSummary; ///// // Status. ///// if (appointment.EventStatus != null) { EventStatusEnum eventStatusEnum = appointment.EventStatus; switch (eventStatusEnum.Alias) { case "core:eventStatusTentative": calendarEvent.Status = Scheduling.iCalendar.EventStatus.Tentative; calendar.Method = Methods.Request; break; case "core:eventStatusConfirmed": calendarEvent.Status = Scheduling.iCalendar.EventStatus.Confirmed; calendar.Method = Methods.Publish; break; case "core:eventStatusCancelled": ///// // If there is no previous iCal UID, ignore this since it is invalid. ///// if (uid == null) { return(null); } calendarEvent.Status = Scheduling.iCalendar.EventStatus.Cancelled; calendar.Method = Methods.Cancel; break; } } else { ///// // New and Updated events must be Requests. ///// calendar.Method = Methods.Request; } ///// // Process the organizer. ///// ProcessOrganizer(calendarEvent, emailAddress); ///// // Process attendees. ///// ProcessAttendees(calendarEvent, appointment); // if there are no attendees there is no iCal appointment if (calendarEvent.Attendees.Count <= 0) { return(null); } if (appointment.ICalAppt.CalendarId == null || appointment.ICalAppt.CalendarId.ICalUid != calendarEvent.Uid) { ///// // Create an iCal UID Container. ///// var container = new ICalUidContainer { ICalUid = calendarEvent.Uid, CalendarEventEmail = appointment.ICalAppt }; ///// // Store the iCal UID in the email message so we can correlate any new proposed times. ///// ///// // Save the container. ///// container.Save( ); } return(calendar); } catch (Exception exc) { EventLog.Application.WriteError("Failed to generate iCalendar attachment." + exc); } return(null); }
/// <summary> /// Executed before the message is saved /// </summary> /// <param name="message"></param> /// <param name="postSaveAction">if not null an action run after the save. This happens even if the save is cancelled.</param> /// <returns> /// True if the save is to be cancelled /// </returns> public bool BeforeSave(ReceivedEmailMessage message, out Action postSaveAction) { postSaveAction = null; ///// // Check the message. ///// if (message == null) { return(false); } var iCalMessage = message.As <ReceivedICalEmailMessage>( ); ///// // Ensure the message is a received iCal email message. ///// if (iCalMessage == null) { return(false); } ///// // The iCalUpdate field was set by the iCalMailMesssageFormatter that was called as part // of the ProcessInboxes action. ///// if (string.IsNullOrEmpty(iCalMessage.ICalUpdate)) { return(false); } ///// // Read the iCal update. ///// using (var sr = new StringReader(iCalMessage.ICalUpdate)) { ///// // Deserialize the string into the iCal object model. ///// IICalendarCollection iCalendarCollection = iCalendar.LoadFromStream(sr); if (iCalendarCollection == null) { return(false); } ///// // Get the first calendar. ///// IICalendar calendar = iCalendarCollection.FirstOrDefault( ); if (calendar == null || calendar.Events == null) { return(false); } ///// // Get the first calendar event. ///// IEvent calendarEvent = calendar.Events.FirstOrDefault( ); if (calendarEvent == null) { return(false); } ///// // Make sure the calendar events UID is set. ///// if (string.IsNullOrEmpty(calendarEvent.Uid)) { return(false); } EventEmail eventEntity = null; Appointment appointment = null; ///// // Find all sent iCal UID containers that correlate to the received calendar events UID. ///// IEnumerable <ICalUidContainer> iCalUidContainers = Entity.GetByField <ICalUidContainer>(calendarEvent.Uid, ICalUidContainer.ICalUid_Field); if (iCalUidContainers != null) { ///// // Get the first sent message. ///// ICalUidContainer iCalUidContainer = iCalUidContainers.FirstOrDefault( ); if (iCalUidContainer != null && iCalUidContainer.CalendarEventEmail != null) { ///// // Get the original event email object that was used to create the sent iCal Email Message. ///// eventEntity = iCalUidContainer.CalendarEventEmail.AsWritable <EventEmail>( ); } } bool modificationsMade = false; if (eventEntity == null) { ///// // No existing event email so this is a new request. ///// EntityRef type = GetEventCreationType(message); eventEntity = type != null?Entity.Create(type).As <EventEmail>( ) : new EventEmail( ); appointment = Entity.Create <Appointment>(); eventEntity.EventEmailAppt = appointment; modificationsMade = true; eventEntity.Name = calendarEvent.Summary; var calUidContainer = new ICalUidContainer { ICalUid = calendarEvent.Uid }; eventEntity.CalendarId = calUidContainer; string creatorEmailAddress = GetEmailAddress(message.EmFrom); if (creatorEmailAddress != null) { EmailContact creatorEmailContact = FindEmailContact(creatorEmailAddress); if (creatorEmailContact == null) { var mailAddress = new MailAddress(message.EmFrom); creatorEmailContact = CreateEmailContact(creatorEmailAddress, mailAddress.DisplayName ?? creatorEmailAddress); } eventEntity.EventEmailCreator = creatorEmailContact; } foreach (IAttendee attendee in calendarEvent.Attendees) { string emailAddress = GetEmailAddress(attendee.Value.ToString( )); if (emailAddress != null) { EmailContact emailContact = FindEmailContact(emailAddress); if (emailContact == null) { CreateEmailContact(emailAddress, attendee.CommonName); } appointment.EventEmailAttendees.Add(emailContact.EmailContactOwner); } } CreateAndSendAcceptance(calendar, iCalMessage, eventEntity); } else { appointment = eventEntity.EventEmailAppt; if (calendar.Method == Methods.Publish || calendar.Method == Methods.Request) { ///// // A REQUEST or PUBLISH means a new event arriving in the system. ///// CreateAndSendAcceptance(calendar, iCalMessage, eventEntity); } } eventEntity.ReceivedEmailMessages.Add(iCalMessage); ///// // Start time. ///// if (calendarEvent.Start != null) { DateTime utcTime = calendarEvent.Start.Utc; if (!Equals(utcTime, appointment.EventStart)) { appointment.EventStart = utcTime; modificationsMade = true; } } ///// // End time. ///// if (calendarEvent.End != null) { DateTime utcTime = calendarEvent.End.Utc; if (!Equals(utcTime, appointment.EventEnd)) { appointment.EventEnd = utcTime; modificationsMade = true; } } ///// // All Day Event. ///// if (appointment.EventIsAllDay == null || !Equals(calendarEvent.IsAllDay, appointment.EventIsAllDay.Value)) { appointment.EventIsAllDay = calendarEvent.IsAllDay; modificationsMade = true; } ///// // Location. ///// if (calendarEvent.Location != null) { if (!Equals(calendarEvent.Location, appointment.EventLocation)) { appointment.EventLocation = calendarEvent.Location; modificationsMade = true; } } ///// // Location. ///// if (eventEntity.EventEmailAppt.EventEmailPriority == null || !Equals(calendarEvent.Priority, eventEntity.EventEmailAppt.EventEmailPriority)) { string priorityAlias; if (calendarEvent.Priority <= 0) { ///// // Undefined. ///// priorityAlias = null; } else if (calendarEvent.Priority <= 4) { ///// // High priority. ///// priorityAlias = "core:highPriority"; } else if (calendarEvent.Priority == 5) { ///// // Normal priority. ///// priorityAlias = "core:normalPriority"; } else if (calendarEvent.Priority <= 9) { ///// // Low priority. ///// priorityAlias = "core:lowPriority"; } else { ///// // Invalid priority. ///// priorityAlias = null; } eventEntity.EventEmailAppt.EventEmailPriority = priorityAlias != null?Entity.Get <EventEmailPriorityEnum>(priorityAlias) : null; modificationsMade = true; } ///// // Status. ///// string statusAlias = null; switch (calendarEvent.Status) { case EventStatus.Cancelled: statusAlias = "core:eventStatusCancelled"; break; case EventStatus.Confirmed: statusAlias = "core:eventStatusConfirmed"; break; case EventStatus.Tentative: statusAlias = "core:eventStatusTentative"; break; } if (!string.IsNullOrEmpty(statusAlias)) { if (appointment.EventStatus == null || appointment.EventStatus.Alias != statusAlias) { appointment.EventStatus = Entity.Get <EventStatusEnum>(statusAlias); modificationsMade = true; } } if (modificationsMade) { CustomContext cc = null; try { string timeZone = null; if (eventEntity != null) { ///// // Find all sent iCal Email Messages that correlate to the received calendar events UID. ///// IEnumerable <SentICalEmailMessage> sentICalEmailMessages = eventEntity.SentEmailMessages; if (sentICalEmailMessages != null) { SentICalEmailMessage sentICalEmailMessage = sentICalEmailMessages.FirstOrDefault(sent => sent.ICalTimeZone != null); if (sentICalEmailMessage != null) { timeZone = sentICalEmailMessage.ICalTimeZone; } } } if (string.IsNullOrEmpty(timeZone)) { if (calendar.TimeZones != null) { ITimeZone calendarTimeZone = calendar.TimeZones.FirstOrDefault( ); if (calendarTimeZone != null) { timeZone = calendarTimeZone.TzId; } } } if (!string.IsNullOrEmpty(timeZone)) { ///// // Set up a custom context just for the duration of this call. ///// RequestContext currentRequestContext = RequestContext.GetContext( ); var data = new RequestContextData(currentRequestContext) { TimeZone = timeZone }; cc = new CustomContext(data); } eventEntity.Save( ); } finally { ///// // Ensure the custom context is disposed. ///// if (cc != null) { cc.Dispose( ); } } } } return(false); }
/// <summary> /// Gets the Ical update. /// </summary> /// <param name="message">The message.</param> /// <param name="receivedICalEmailMessage">The received I cal email message.</param> /// <param name="iCal">The i cal.</param> /// <returns></returns> private static MailMessageFormatterResult GetICalUpdate(MailMessage message, ReceivedICalEmailMessage receivedICalEmailMessage, out string iCal) { iCal = null; if (message == null) { return(MailMessageFormatterResult.Skip); } try { var attachableItems = new List <AttachmentBase>( ); attachableItems.AddRange(message.AlternateViews); attachableItems.AddRange(message.Attachments); ///// // Locate a view that contains a calendar attachment. ///// foreach (AttachmentBase attachment in attachableItems) { if (attachment.ContentType.MediaType == "text/calendar") { ///// // Deserialize the iCalendar attachment. ///// IICalendarCollection iCalendarCollection = iCalendar.LoadFromStream(attachment.ContentStream); if (iCalendarCollection != null) { IICalendar calendar = iCalendarCollection.FirstOrDefault( ); if (calendar != null) { if (calendar.Method == Methods.Reply) { IEvent calendarEvent = calendar.Events.FirstOrDefault( ); if (calendarEvent != null && !string.IsNullOrEmpty(calendarEvent.Uid)) { ///// // Find all iCal UID containers that correlate to the received calendar events UID. ///// IEnumerable <ICalUidContainer> iCalUidContainers = Entity.GetByField <ICalUidContainer>(calendarEvent.Uid, ICalUidContainer.ICalUid_Field); if (iCalUidContainers != null) { ///// // Get the first iCal UID container. ///// ICalUidContainer iCalUidContainer = iCalUidContainers.FirstOrDefault( ); if (iCalUidContainer != null && iCalUidContainer.CalendarEventEmail != null) { ///// // Get the original event email object that was used to calendar UID container. ///// EventEmail eventEntity = iCalUidContainer.CalendarEventEmail; if (eventEntity != null) { // *************** // This needs to be fixed as part of dealing with replies from ical requests. The rel on a rel needs to be turned into something else. // *************** //IEntityRelationship<EventEmailAttendees, EmailContact> attendeeRelationshipInstance = FindAttendeeRelationshipInstance( eventEntity, message.From.Address.ToLowerInvariant( ) ); //if ( attendeeRelationshipInstance != null ) //{ // Attendee attendee = FindICalAttendee( calendarEvent, message.From.Address.ToLowerInvariant( ) ); // if ( attendee != null ) // { // var eventEmailAttendees = attendeeRelationshipInstance.Instance.AsWritable<EventEmailAttendees>( ); // switch ( attendee.ParticipationStatus ) // { // case ParticipationStatus.Accepted: // eventEmailAttendees.AttendeeStatus_Enum = AttendeeStatusEnum_Enumeration.AttendeeStatusAccepted; // break; // case ParticipationStatus.Declined: // eventEmailAttendees.AttendeeStatus_Enum = AttendeeStatusEnum_Enumeration.AttendeeStatusDeclined; // break; // case ParticipationStatus.Delegated: // eventEmailAttendees.AttendeeStatus_Enum = AttendeeStatusEnum_Enumeration.AttendeeStatusDelegated; // break; // case ParticipationStatus.NeedsAction: // eventEmailAttendees.AttendeeStatus_Enum = AttendeeStatusEnum_Enumeration.AttendeeStatusNeedsAction; // break; // case ParticipationStatus.Tentative: // eventEmailAttendees.AttendeeStatus_Enum = AttendeeStatusEnum_Enumeration.AttendeeStatusTentative; // break; // } // eventEmailAttendees.Save( ); // } //} //************* receivedICalEmailMessage.CreatedEventEmail = eventEntity; ///// // Save the message since the process inbox action will discard it. ///// receivedICalEmailMessage.Save( ); } } } } return(MailMessageFormatterResult.Reject); } ///// // Serialize the iCalendar to a string for storage. ///// var serializer = new iCalendarSerializer( ); iCal = serializer.SerializeToString(calendar); return(MailMessageFormatterResult.Ok); } } break; } } } catch (Exception exc) { EventLog.Application.WriteError("Failed to process email iCal attachment. " + exc); return(MailMessageFormatterResult.Error); } return(MailMessageFormatterResult.Skip); }