Ejemplo n.º 1
1
        private void GetMeetingHeaders(MeetingItem item, out string smallHead, string[] exclusions)
        {
            StringBuilder header = new StringBuilder();
            if (!exclusions.Contains("title", StringComparer.OrdinalIgnoreCase))
            {
                header.Append("<p>");
                AppendTitle(item, header, true);
            }

            AppendPplAndTime(item, header, exclusions);

            var appointment = item.GetAssociatedAppointment(false);
            if (appointment != null)
            {
            string when = appointment.Start.Date.Equals(appointment.End.Date)
             ? string.Format("from {0:h:mm tt} to {1:h:mm tt}, {2:dddd, MMMM d yyyy}", appointment.Start, appointment.End, appointment.Start)
             : string.Format("from {0:h:mm tt dddd, MMMM d yyyy} to {1:h:mm tt dddd, MMMM d yyyy}", appointment.Start, appointment.End);
            header.AppendFormat("<br/>{0}", when);
            if (!string.IsNullOrWhiteSpace(appointment.Location))
                header.AppendFormat("<br/>at {0}", appointment.Location);
            }

            AddAttachments(header, item.Attachments);
            if (!exclusions.Contains("title", StringComparer.OrdinalIgnoreCase))
            header.Append("</p>");
            smallHead = header.ToString();
        }
        /// <summary>
        /// Applies the appropiate rule to the meeting parameter
        /// </summary>
        /// <param name="meetingItem">The meeting that needs processing</param>
        /// <param name="rule">the associated decline rule for the folder of this meetingItem</param>
        private static void ProcessRule(MeetingItem meetingItem, DeclineRuleSetting rule)
        {
            // if it's a Cancelation, delete it from calendar
            if (meetingItem.Class == OlObjectClass.olMeetingCancellation)
            {
                if (meetingItem.GetAssociatedAppointment(false) != null)
                {
                    meetingItem.GetAssociatedAppointment(false).Delete(); return;
                }
                meetingItem.Delete(); return; // if deleted by user/app, delete the whole message
            }

            // get associated appointment
            AppointmentItem appointment         = meetingItem.GetAssociatedAppointment(false);
            string          globalAppointmentID = appointment.GlobalAppointmentID;

            // optional, send notification back to sender
            appointment.ResponseRequested &= rule.SendResponse;

            // set decline to the meeting
            MeetingItem responseMeeting = appointment.Respond(rule.Response, true);

            // https://msdn.microsoft.com/en-us/VBA/Outlook-VBA/articles/appointmentitem-respond-method-outlook
            // says that Respond() will return a new meeting object for Tentative response

            // optional, add a meesage to the Body
            if (!String.IsNullOrEmpty(rule.Message))
            {
                (responseMeeting ?? meetingItem).Body = rule.Message;
            }

            // send decline
            //if(rule.Response == OlMeetingResponse.olMeetingDeclined)
            (responseMeeting ?? meetingItem).Send();

            // and delete the appointment if tentative
            if (rule.Response == OlMeetingResponse.olMeetingTentative)
            {
                appointment.Delete();
            }

            // after Sending the response, sometimes the appointment doesn't get deleted from calendar,
            // but appointmnent could become and invalid object, so we need to search for it and delete it
            AppointmentItem newAppointment = (AppointmentItem)Globals.AddIn.Application.Session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar).Items
                                             .Find("@SQL=\"http://schemas.microsoft.com/mapi/id/{6ED8DA90-450B-101B-98DA-00AA003F1305}/00030102\" = '"
                                                   + globalAppointmentID + "' ");

            if (newAppointment != null)
            {
                newAppointment.Delete();
            }
        }
Ejemplo n.º 3
0
        private void GetMeetingHeaders(MeetingItem item, out string smallHead, string[] exclusions)
        {
            StringBuilder header = new StringBuilder();

            if (!exclusions.Contains("title", StringComparer.OrdinalIgnoreCase))
            {
                header.Append("<p>");
                AppendTitle(item, header, true);
            }

            AppendPplAndTime(item, header, exclusions);

            var appointment = item.GetAssociatedAppointment(false);

            if (appointment != null)
            {
                string when = appointment.Start.Date.Equals(appointment.End.Date)
     ? string.Format("from {0:h:mm tt} to {1:h:mm tt}, {2:dddd, MMMM d yyyy}", appointment.Start, appointment.End, appointment.Start)
     : string.Format("from {0:h:mm tt dddd, MMMM d yyyy} to {1:h:mm tt dddd, MMMM d yyyy}", appointment.Start, appointment.End);
                header.AppendFormat("<br/>{0}", when);
                if (!string.IsNullOrWhiteSpace(appointment.Location))
                {
                    header.AppendFormat("<br/>at {0}", appointment.Location);
                }
            }

            AddAttachments(header, item.Attachments);
            if (!exclusions.Contains("title", StringComparer.OrdinalIgnoreCase))
            {
                header.Append("</p>");
            }
            smallHead = header.ToString();
        }
Ejemplo n.º 4
0
        private SyncResult synchronize()
        {
            Console console = Forms.Main.Instance.Console;

            console.Update("Finding Calendar Entries", Console.Markup.mag_right, newLine: false);

            List <AppointmentItem> outlookEntries = null;
            List <Event>           googleEntries  = null;

            try {
                #region Read Outlook items
                console.Update("Scanning Outlook calendar...");
                outlookEntries = OutlookOgcs.Calendar.Instance.GetCalendarEntriesInRange(false);
                console.Update(outlookEntries.Count + " Outlook calendar entries found.", Console.Markup.sectionEnd, newLine: false);

                if (CancellationPending)
                {
                    return(SyncResult.UserCancelled);
                }
                #endregion

                #region Read Google items
                console.Update("Scanning Google calendar...");
                try {
                    googleEntries = GoogleOgcs.Calendar.Instance.GetCalendarEntriesInRange();
                } catch (AggregateException agex) {
                    OGCSexception.AnalyseAggregate(agex);
                } catch (Google.Apis.Auth.OAuth2.Responses.TokenResponseException ex) {
                    OGCSexception.AnalyseTokenResponse(ex, false);
                    return(SyncResult.Fail);
                } catch (System.Net.Http.HttpRequestException ex) {
                    OGCSexception.Analyse(ex);
                    ex.Data.Add("OGCS", "ERROR: Unable to connect to the Google calendar. Please try again.");
                    throw ex;
                } catch (System.Exception ex) {
                    OGCSexception.Analyse(ex);
                    ex.Data.Add("OGCS", "ERROR: Unable to connect to the Google calendar.");
                    if (OGCSexception.GetErrorCode(ex) == "0x8013153B") //ex.Message == "A task was canceled." - likely timed out.
                    {
                        ex.Data["OGCS"] += " Please try again.";
                    }
                    throw ex;
                }
                Recurrence.Instance.SeparateGoogleExceptions(googleEntries);
                if (Recurrence.Instance.GoogleExceptions != null && Recurrence.Instance.GoogleExceptions.Count > 0)
                {
                    console.Update(googleEntries.Count + " Google calendar entries found.");
                    console.Update(Recurrence.Instance.GoogleExceptions.Count + " are exceptions to recurring events.", Console.Markup.sectionEnd, newLine: false);
                }
                else
                {
                    console.Update(googleEntries.Count + " Google calendar entries found.", Console.Markup.sectionEnd, newLine: false);
                }

                if (CancellationPending)
                {
                    return(SyncResult.UserCancelled);
                }
                #endregion

                #region Normalise recurring items in sync window
                console.Update("Total inc. recurring items spanning sync date range...");
                //Outlook returns recurring items that span the sync date range, Google doesn't
                //So check for master Outlook items occurring before sync date range, and retrieve Google equivalent
                for (int o = outlookEntries.Count - 1; o >= 0; o--)
                {
                    log.Fine("Processing " + (o + 1) + "/" + outlookEntries.Count);
                    AppointmentItem ai = null;
                    try {
                        if (outlookEntries[o] is AppointmentItem)
                        {
                            ai = outlookEntries[o];
                        }
                        else if (outlookEntries[o] is MeetingItem)
                        {
                            log.Info("Calendar object appears to be a MeetingItem, so retrieving associated AppointmentItem.");
                            MeetingItem mi = outlookEntries[o] as MeetingItem;
                            outlookEntries[o] = mi.GetAssociatedAppointment(false);
                            ai = outlookEntries[o];
                        }
                        else
                        {
                            log.Warn("Unknown calendar object type - cannot sync it.");
                            skipCorruptedItem(ref outlookEntries, outlookEntries[o], "Unknown object type.");
                            outlookEntries[o] = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(outlookEntries[o]);
                            continue;
                        }
                    } catch (System.Exception ex) {
                        log.Warn("Encountered error casting calendar object to AppointmentItem - cannot sync it.");
                        log.Debug(ex.Message);
                        skipCorruptedItem(ref outlookEntries, outlookEntries[o], ex.Message);
                        outlookEntries[o] = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(outlookEntries[o]);
                        ai = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(ai);
                        continue;
                    }

                    //Now let's check there's a start/end date - sometimes it can be missing, even though this shouldn't be possible!!
                    String entryID;
                    try {
                        entryID = outlookEntries[o].EntryID;
                        DateTime checkDates = ai.Start;
                        checkDates = ai.End;
                    } catch (System.Exception ex) {
                        log.Warn("Calendar item does not have a proper date range - cannot sync it.");
                        log.Debug(ex.Message);
                        skipCorruptedItem(ref outlookEntries, outlookEntries[o], ex.Message);
                        outlookEntries[o] = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(outlookEntries[o]);
                        ai = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(ai);
                        continue;
                    }

                    if (ai.IsRecurring && ai.Start.Date < Settings.Instance.SyncStart && ai.End.Date < Settings.Instance.SyncStart)
                    {
                        //We won't bother getting Google master event if appointment is yearly reoccurring in a month outside of sync range
                        //Otherwise, every sync, the master event will have to be retrieved, compared, concluded nothing's changed (probably) = waste of API calls
                        RecurrencePattern oPattern = ai.GetRecurrencePattern();
                        try {
                            if (oPattern.RecurrenceType.ToString().Contains("Year"))
                            {
                                log.Fine("It's an annual event.");
                                Boolean  monthInSyncRange = false;
                                DateTime monthMarker      = Settings.Instance.SyncStart;
                                while (Convert.ToInt32(monthMarker.ToString("yyyyMM")) <= Convert.ToInt32(Settings.Instance.SyncEnd.ToString("yyyyMM")) &&
                                       !monthInSyncRange)
                                {
                                    if (monthMarker.Month == ai.Start.Month)
                                    {
                                        monthInSyncRange = true;
                                    }
                                    monthMarker = monthMarker.AddMonths(1);
                                }
                                log.Fine("Found it to be " + (monthInSyncRange ? "inside" : "outside") + " sync range.");
                                if (!monthInSyncRange)
                                {
                                    outlookEntries.Remove(ai); log.Fine("Removed."); continue;
                                }
                            }
                            Event masterEv = Recurrence.Instance.GetGoogleMasterEvent(ai);
                            if (masterEv != null && masterEv.Status != "cancelled")
                            {
                                Event cachedEv = googleEntries.Find(x => x.Id == masterEv.Id);
                                if (cachedEv == null)
                                {
                                    googleEntries.Add(masterEv);
                                }
                                else
                                {
                                    if (masterEv.Updated > cachedEv.Updated)
                                    {
                                        log.Debug("Refreshing cache for this Event.");
                                        googleEntries.Remove(cachedEv);
                                        googleEntries.Add(masterEv);
                                    }
                                }
                            }
                        } catch (System.Exception ex) {
                            console.Update("Failed to retrieve master for Google recurring event outside of sync range.", Console.Markup.error);
                            throw ex;
                        } finally {
                            oPattern = (RecurrencePattern)OutlookOgcs.Calendar.ReleaseObject(oPattern);
                        }
                    }
                    //Completely dereference object and retrieve afresh (due to GetRecurrencePattern earlier)
                    ai = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(ai);
                    OutlookOgcs.Calendar.Instance.IOutlook.GetAppointmentByID(entryID, out ai);
                    outlookEntries[o] = ai;
                }
                console.Update("Outlook " + outlookEntries.Count + ", Google " + googleEntries.Count);

                GoogleOgcs.Calendar.ExportToCSV("Outputting all Events.", "google_events.csv", googleEntries);
                OutlookOgcs.Calendar.ExportToCSV("Outputting all Appointments.", "outlook_appointments.csv", outlookEntries);
                if (CancellationPending)
                {
                    return(SyncResult.UserCancelled);
                }
                #endregion

                Boolean success    = true;
                String  bubbleText = "";
                if (Settings.Instance.SyncDirection != Direction.GoogleToOutlook)
                {
                    success = outlookToGoogle(outlookEntries, googleEntries, ref bubbleText);
                    if (CancellationPending)
                    {
                        return(SyncResult.UserCancelled);
                    }
                }
                if (!success)
                {
                    return(SyncResult.Fail);
                }
                if (Settings.Instance.SyncDirection != Direction.OutlookToGoogle)
                {
                    if (bubbleText != "")
                    {
                        bubbleText += "\r\n";
                    }
                    success = googleToOutlook(googleEntries, outlookEntries, ref bubbleText);
                    if (CancellationPending)
                    {
                        return(SyncResult.UserCancelled);
                    }
                }
                if (bubbleText != "")
                {
                    Forms.Main.Instance.NotificationTray.ShowBubbleInfo(bubbleText);
                }

                return(SyncResult.OK);
            } finally {
                for (int o = outlookEntries.Count() - 1; o >= 0; o--)
                {
                    outlookEntries[o] = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(outlookEntries[o]);
                    outlookEntries.RemoveAt(o);
                }
            }
        }
Ejemplo n.º 5
0
        private void Items_ItemAdd(object item)
        {
            MeetingItem meetingItem = item as MeetingItem;

            if (meetingItem != null)
            {
                var apptItem = meetingItem.GetAssociatedAppointment(false);
                if (apptItem != null)
                {
                    var organizerAddressEntry   = apptItem.GetOrganizer();
                    var currentUserAddressEntry = apptItem.Session?.CurrentUser?.AddressEntry;

                    CreateEmailItem(
                        subjectEmail: $"Oofer debug: {meetingItem.Subject}",
                        toEmail: currentUserAddressEntry.Address,
                        bodyEmail: $"This meeting item was received:\n\n{meetingItem.Subject}");

                    var alias = string.Empty;

                    if (organizerAddressEntry.Type == "EX")
                    {
                        var exchangeUser = organizerAddressEntry.GetExchangeUser();
                        alias = exchangeUser.Alias;
                    }

                    var organizerFirstName = organizerAddressEntry.Name.Split(' ').FirstOrDefault();

                    if (_matches.Any(x => apptItem.Subject.ToUpperInvariant().Contains(x)) &&
                        organizerAddressEntry != currentUserAddressEntry)
                    {
                        var needsAlias = !string.IsNullOrWhiteSpace(alias) &&
                                         !apptItem.Subject.Contains(organizerFirstName) &&
                                         !apptItem.Subject.Contains(alias);

                        if (apptItem.ReminderSet ||
                            apptItem.BusyStatus != OlBusyStatus.olFree ||
                            apptItem.ResponseRequested == true ||
                            needsAlias)
                        {
                            var subjectText           = apptItem.Subject;
                            var busyStatusText        = GetBusyStatusString(apptItem.BusyStatus);
                            var reminderSetText       = apptItem.ReminderSet ? "Reminder was set" : "Reminder was not set";
                            var responseRequestedText = apptItem.ResponseRequested ? "Response was requested" : "Response was not requested";

                            apptItem.BusyStatus        = OlBusyStatus.olFree;
                            apptItem.ReminderSet       = false;
                            apptItem.ResponseRequested = false;

                            if (needsAlias)
                            {
                                apptItem.Subject = $"{alias}: {subjectText}";
                            }

                            // We will not send the response, but want to accept the appointment on our side. See linked
                            // docs to send the response, if desired.
                            apptItem.Respond(OlMeetingResponse.olMeetingAccepted, true, Type.Missing);
                            apptItem.UnRead = false;

                            apptItem.Save();

                            meetingItem.UnRead = false;
                            meetingItem.Save();

                            CreateEmailItem(
                                subjectEmail: $"Cleaned OOF/WFH: {subjectText}",
                                toEmail: currentUserAddressEntry.Address,
                                bodyEmail: $"This appointment was cleaned:\n\n{apptItem.Subject}\n{busyStatusText}\n{reminderSetText}\n{responseRequestedText}");
                        }
                    }
                }
            }
        }