Ejemplo n.º 1
0
        /// <summary>
        /// Called one at startup, after an initial delay to let outlook finish loading
        /// </summary>
        void performDelayedStartupTasks()
        {
            // This code is only for diagnosing tricky problems and won't be executed in a normal deployment
            if (!logger.Enabled)
            {
                return;
            }

            // iterate over all of today's items
            logger.Debug("Advanced diagnostics: logging data on items in today's calendar...");
            Outlook.Items calItems = findCalendarItems(
                "[Start] >= '" + (DateTime.Today).ToString("g") + "'"
                + " AND [Start] <= '" + (DateTime.Today + OneDay).ToString("g") + "'"
                + " AND [End] >= '" + (DateTime.Today).ToString("g") + "'"
                // not really necessary but
                + " AND [End] <= '" + (DateTime.Today + OneDay).ToString("g") + "'"
                );
            var subjectExcludeRegex = getSubjectExcludeRegex();
            int count = 0;

            foreach (Outlook.AppointmentItem item in calItems)
            {
                count++;
                if (string.IsNullOrWhiteSpace(item.Subject))
                {
                    logger.Debug("Found meeting with subject '" + item.Subject + "' at " + item.Start);
                }

                if (item.AllDayEvent)
                {
                    continue;                                   // else constructor will throw
                }
                var meeting = new UpcomingMeeting(item, item.Start - DefaultReminderTime);
                if (meeting.GetMeetingUrl() != "")
                {
                    logger.Debug("Extracted meeting URL from '" + meeting.Subject + "': '" + meeting.GetMeetingUrl() + "'");
                }
                else if (meeting.Body.Trim() != "")
                {
                    // This is a bit verbose but may be needed sometimes for debugging URL regexes (at least until we build a proper UI for that task)
                    logger.Info("No meeting URL found in '" + meeting.Subject + "': \n-------------------------------------\n" + meeting.Body + "\n-------------------------------------\n");
                }
                if (subjectExcludeRegex != null && subjectExcludeRegex.IsMatch(item.Subject ?? ""))
                {
                    logger.Info("This item will be ignored due to subject exclude regex: '" + item.Subject + "'");
                }
            }
            logger.Debug("Completed advanced diagnostics - checked " + count + " calendar items for today\n\n");
        }
Ejemplo n.º 2
0
        private void updateUpcomingMeetings()
        {
            DateTime now = DateTime.Now;

            // first update existing items in case there were any changes
            foreach (UpcomingMeeting m in upcoming.Values)
            {
                // if start date was changed in either direction we should recalculate
                // the reminder - might need a notification sooner,
                // or if the meeting was postponed then later.
                // always resetting to defaultremindertime is the safest/most conservative
                // option since it gives maximum opportunity for the user to decide
                // whether to defer the meeting
                if (m.UpdateStartTime())
                {
                    logger.Info("Resetting reminder time for " + m + " due to change in start time");
                    m.NextReminderTime = m.StartTime - DefaultReminderTime;
                }
            }

            // add in any new meetings we're not aware of yet that will start or need to be reminded about in the
            // next sleep interval, ignoring any that have ended already
            // this filter is conservative - must not miss any items, but is ok if it contains some extra ones

            // we use lastMeetingSearchTime as the lower bound to avoid missing stuff, but give up and just
            // do it from 'now' onwards if we haven't checked for a day or more, since it's too late anyway by then
            if (now - lastMeetingSearchTime > OneDay)
            {
                lastMeetingSearchTime = now;
            }

            Outlook.Items calItems = findCalendarItems(
                "[Start] >= '" + (lastMeetingSearchTime).ToString("g") + "'"
                + " AND [Start] <= '" + (now + SleepInterval + DefaultReminderTime).ToString("g") + "'"
                + " AND [End] >= '" + (now).ToString("g") + "'"
                // not really necessary but
                + " AND [End] <= '" + (now + OneDay).ToString("g") + "'"
                );

            // next time we'll monitor from now on
            lastMeetingSearchTime = now;

            /*
             * filter = "[Start] >= '" + new DateTime(2016, 1, 17).ToString("g") + "'"
             + " AND [Start] <= '" + new DateTime(2016, 1, 19).ToString("g") + "'"
             + " AND [End] >= '" + new DateTime(2016, 1, 17).ToString("g") + "'"
             + " AND [End] <= '" + new DateTime(2016, 1, 19).ToString("g") + "'"
             +                              ;
             * */

            Regex subjectExcludeRegex = getSubjectExcludeRegex();

            foreach (Outlook.AppointmentItem item in calItems)
            {
                if (item.AllDayEvent)
                {
                    continue;
                }

                if (subjectExcludeRegex != null && subjectExcludeRegex.IsMatch(item.Subject ?? ""))
                {
                    logger.Debug("Ignoring excluded meeting based on subject: " + item.Subject);
                    continue;
                }

                if (UpcomingMeeting.IsAppointmentCancelled(item))
                {
                    logger.Debug("Ignoring cancelled meeting: " + item.Subject);
                    continue;
                }

                //logger.Debug("Returned: " + new UpcomingMeeting(item, item.Start - DefaultReminderTime)); // TODO; remove
                // nb: the second check should be unecessary, but prevents bad behaviour if outlook's filtering doesn't work right for some reason
                if (!upcoming.ContainsKey(item.EntryID) && item.End >= now)
                {
                    upcoming.Add(item.EntryID, new UpcomingMeeting(item, item.Start - DefaultReminderTime));
                }
            }

            // finally, expire any meetings that have ended (we can't expire items until they definitely
            // won't show up in the above filter otherwise we might end up re-adding dismissed reminders)
            // probably safe to expire them even if not dismissed, if they've ended
            var expired = new List <string>(upcoming.Values.Where(e => (e.EndTime < now) || e.IsDeleted).Select(e => e.ID));

            foreach (var id in expired)
            {
                logger.Debug("Removing expired item: " + upcoming[id]);
                upcoming[id].Dispose();
                upcoming.Remove(id);
            }
            logger.Debug(upcoming.Count + " upcoming items: " + string.Join("\n	  ", upcoming.Values));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Called when the timer wakes up or when a reminder form has been closed to work out
        /// what to do next
        /// </summary>
        private void waitOrRemind()
        {
            try
            {
                DateTime now = DateTime.Now;
                updateUpcomingMeetings();


                UpcomingMeeting next = null;
                if (upcoming.Count > 0)
                {
                    next = upcoming.Values.OrderBy(m => m.NextReminderTime).First();
                    if (next.IsDismissed)                     // implies it contains only expired items
                    {
                        next = null;
                    }
                }

                DateTime sleepUntil = now + SleepInterval;

                if (next != null)
                {
                    // either we wokeup just in time or maybe we have a backlog of reminder(s) to clear
                    // (nb: use 500ms fudge factor to make sure potentially imprecise timers don't hurt us)
                    if (next.NextReminderTime <= now + new TimeSpan(0, 0, 0, 0, 500))
                    {
                        logger.Info("Showing reminder for: " + next);
                        playReminderSound();
                        ReminderForm form = new ReminderForm(next);
                        form.FormClosed += ReminderFormClosedEventHandler;
                        form.Show();
                        // timers etc are disabled until the current window has been closed -
                        // simpler to manage and avoids getting a million popups if you leave it running while on vacation
                        return;
                    }

                    if (next.NextReminderTime < sleepUntil)
                    {
                        sleepUntil = next.NextReminderTime;
                    }
                }

                myTimer.Interval = Convert.ToInt32((sleepUntil - now).TotalMilliseconds);
                if (myTimer.Interval <= 0)
                {
                    // should never happen
                    logger.Info("Warning: attempted to set invalid interval of " + myTimer.Interval + "; next=" + next);
                    myTimer.Interval = 100;
                }
                nextPlannedWakeup = sleepUntil;                 // used to measure lateness
                logger.Debug("Setting timer to wait in " + myTimer.Interval + " at " + sleepUntil);
                myTimer.Start();

                if (DateTime.Now - now > new TimeSpan(0, 0, 0, 0, 500))
                {
                    logger.Debug("waitOrRemind took a long time: " + (DateTime.Now - now));
                }
            }
            catch (Exception ex)
            {
                logger.Error("Unexpected error in waitOrRemind: ", ex);
                // don't throw out of here as it could result in the dialog being uncloseable
            }
        }
Ejemplo n.º 4
0
        public ReminderForm(UpcomingMeeting meeting)
        {
            this.meeting = meeting;
            this.joinUrl = meeting.GetMeetingUrl();
            InitializeComponent();

            // populate the combo with a hardcoded list of items whose primary purpose is to illustrate the
            // syntax of all possible values
            timeCombo.Items.Add(new SnoozeTime(20, false));
            timeCombo.Items.Add(new SnoozeTime(-20, false));
            timeCombo.Items.Add(new SnoozeTime(30, true));
            timeCombo.Items.Add(new SnoozeTime(60, true));

            // set labels for this meeting
            nameLabel.Text      = meeting.Subject;
            extraInfoLabel.Text = "";
            if (meeting.Location.Length > 0)
            {
                extraInfoLabel.Text = "Location: " + meeting.Location + "; ";
            }
            extraInfoLabel.Text += "Duration " + meeting.OutlookItem.Duration + " mins";

            if (meeting.getOrganizer() != null)
            {
                extraInfoLabel.Text += "; organizer: " + meeting.getOrganizer();
            }
            IEnumerable <string> attendees = meeting.GetAttendees();

            if (attendees.Count() == 1)
            {
                extraInfoLabel.Text += "; with: " + string.Join(", ", attendees);
            }
            else
            {
                extraInfoLabel.Text += "; " + attendees.Count() + " attendees";
            }
            extraInfoLabel.Text += "";

            toolTip.SetToolTip(nameLabel, nameLabel.Text);             // in case it's too long
            toolTip.SetToolTip(extraInfoLabel, meeting.Body);

            joinButton.Visible = joinUrl.Length > 0;

            // start time timer
            timer.Enabled = true;
            updateStartTime();

            // reminder times list. stored in MRU order but sorted in time order
            timeList.Items.Clear();

            var list = SnoozeTime.ParseList(Properties.Settings.Default.mruSnoozeTimes);

            if (list.Count == 0)
            {
                // initialize default list of snooze times
                list.Add(new SnoozeTime(-2 * 60, false));
                list.Add(new SnoozeTime(-30, false));
                list.Add(new SnoozeTime(30, true));
                list.Add(new SnoozeTime(60, true));
                list.Add(new SnoozeTime(60 * 5, true));
                Properties.Settings.Default.mruSnoozeTimes = SnoozeTime.ListToString(list);
                Properties.Settings.Default.Save();
            }
            list.Sort();
            list.ForEach(st => timeList.Items.Add(st));

            // by default, dismiss when dialog is closed. unless snooze is selected
            meeting.Dismiss();

            reactivateTime = DateTime.Now + reactivateTimeSpan;
        }