public EventCacheEntry(Event @event, string fromAccount)
        {
            Event       = @event;
            FromAccount = fromAccount;
            if (!string.IsNullOrEmpty(@event.Description) &&
                Event.Description.Contains("Added by OutlookGoogleSync (" + fromAccount + "):"))
            {
                IsSyncItem = true;
            }

            if (Event.Start != null)
            {
                if (Event.Start.DateTime == null)
                {
                    Event.Start.DateTime = GoogleCalendar.GoogleTimeFrom(DateTime.Parse(Event.Start.Date));
                }
                if (Event.End.DateTime == null)
                {
                    Event.End.DateTime = GoogleCalendar.GoogleTimeFrom(DateTime.Parse(Event.End.Date));
                }

                Signature = (Event.Start.DateTime + ";" + Event.End.DateTime + ";" + Event.Summary + ";" + Event.Location).Trim();
            }
            else
            {
                Signature = (Event.Status + ";" + Event.Summary + ";" + Event.Location).Trim();
            }
        }
        private void buttonGetMyGoogleCalendars_Click(object sender, EventArgs e)
        {
            buttonGetMyCalendars.Enabled = false;
            comboBoxCalendars.Enabled    = false;

            try
            {
                GoogleCalendar gcal = new GoogleCalendar();
                List <GoogleCalendarListEntry> calendars = gcal.getCalendars();
                if (calendars != null)
                {
                    comboBoxCalendars.Items.Clear();
                    foreach (GoogleCalendarListEntry mcle in calendars)
                    {
                        comboBoxCalendars.Items.Add(mcle);
                    }

                    comboBoxCalendars.SelectedIndex = 0;
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Error:\r\n" + ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            buttonGetMyCalendars.Enabled = true;
            comboBoxCalendars.Enabled    = true;
        }
Beispiel #3
0
        public AppointmentItemCacheEntry(AppointmentItem appointmentItem, string fromAccount)
        {
            AppointmentItem = appointmentItem;
            FromAccount     = fromAccount;

            Signature = (GoogleCalendar.GoogleTimeFrom(appointmentItem.Start) + ";" +
                         GoogleCalendar.GoogleTimeFrom(appointmentItem.End) + ";" +
                         appointmentItem.Subject + ";" + appointmentItem.Location).Trim();
        }
        private void deleteAllSyncItems()
        {
            DateTime        syncStarted = DateTime.Now;
            OutlookCalendar ocal        = null;

            try
            {
                logboxout("Sync started at " + syncStarted.ToString());
                logboxout("--------------------------------------------------");

                ocal = new OutlookCalendar();

                logboxout("Reading Google Calendar Entries...");
                GoogleCalendar gcal                  = new GoogleCalendar();
                List <Event>   GoogleEntries         = gcal.getCalendarEntriesInRange(syncStarted);
                List <Event>   GoogleEntriesToDelete = new List <Event>();
                foreach (Event ev in GoogleEntries)
                {
                    if (!string.IsNullOrEmpty(ev.Description) &&
                        ev.Description.Contains("Added by OutlookGoogleSync (" + ocal.AccountName + "):"))
                    {
                        GoogleEntriesToDelete.Add(ev);
                    }
                }

                logboxout("Deleting " + GoogleEntriesToDelete.Count + " Google Calendar Sync Entries...");
                foreach (Event ev in GoogleEntriesToDelete)
                {
                    if (!string.IsNullOrEmpty(ev.Description) &&
                        ev.Description.Contains("Added by OutlookGoogleSync (" + ocal.AccountName + "):"))
                    {
                        gcal.deleteCalendarEntry(ev);
                    }
                }

                logboxout("Done.");
                logboxout("--------------------------------------------------");

                DateTime syncFinished = DateTime.Now;
                TimeSpan elapsed      = syncFinished - syncStarted;
                logboxout("Sync finished at " + syncFinished.ToString());
                logboxout("Time needed: " + elapsed.Minutes + " min " + elapsed.Seconds + " s");
            }
            catch (System.Exception ex)
            {
                logboxout("Error Syncing:\r\n" + ex.ToString());
            }

            freeCOMResources(ocal, null);
        }
        bool synchronize(List <AppointmentItem> outlook_items, List <Event> google_items)
        {
            // TODO: consider description updates (only needs to be considered when checked... come back and fix this)
            // TODO: optimize comparison algorithms - this one not mine, but should consider for larger sets of data
            // TODO: outlook to google recurrence 90% complete
            //       getting weird error message from outlook: "The operation cannot be performed because the message has changed"
            //       need to determine what happens when deleting just the master recurrence object
            // TODO: google to outlook recurrence 0% complete... need to read up on http://www.ietf.org/rfc/rfc2445
            // TODO: testing on a larger scale...
            // TODO: refactor this function, as it is getting out of control...

            // indicates the number of entries added / updated / removed....
            uint google_entries_added    = 0;
            uint google_entries_updated  = 0;
            uint google_entries_removed  = 0;
            uint outlook_entries_added   = 0;
            uint outlook_entries_updated = 0;
            uint outlook_entries_removed = 0;
            uint bound_entries_found     = 0;
            uint errors = 0;

            // first synchronize outlook -> google

            // run over all the office items and add or update on google
            for (int i = outlook_items.Count - 1; i >= 0; --i)
            {
                // obtain a reference to the outlook item...
                var oitem = outlook_items[i];

                // determine first if this outlook item is associated with a google calendar item...
                UserProperty oitem_google_prop = oitem.UserProperties.Find(EventPropertyKey);

                if (oitem_google_prop == null)
                {
                    // run across the google events to see if there is one that matches
                    Event gitem = null;
                    foreach (var g in google_items)
                    {
                        // lowercase match the signature and
                        // the property is not set or the property matches the oitem, match found...
                        // the user has to type it the same in both cases to make a match...
                        // is there something better here?
                        if (signature(g).ToLower() == signature(oitem).ToLower() &&
                            (g.ExtendedProperties == null ||
                             g.ExtendedProperties.Shared == null ||
                             g.ExtendedProperties.Shared.ContainsKey(EventPropertyKey) == false ||
                             g.ExtendedProperties.Shared[EventPropertyKey] == OutlookCalendar.FormatEventID(oitem)))
                        {
                            gitem = g; break;
                        }
                    }

                    if (gitem != null)
                    {
                        // give some indication of what will take place
                        logboxout("Binding Outlook and Google event: " + oitem.Subject + " (" + oitem.Start + ")");

                        // bind the properties together
                        OutlookCalendar.Instance.Bind(oitem, gitem);

                        // update the instance on the google calendar
                        GoogleCalendar.Instance.updateEntry(gitem);

                        // remove the outlook item and the google item from the lists...
                        // do not need to process them again for future iterations...
                        google_items.Remove(gitem);
                        outlook_items.Remove(oitem);

                        // save and close the outlook item
                        ((_AppointmentItem)oitem).Close(OlInspectorClose.olSave);

                        // remove the com reference
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem);

                        // update the stats
                        ++bound_entries_found;
                    }
                    else
                    {
                        // give some indication of what will take place
                        logboxout("Creating Google event: " + oitem.Subject + " (" + oitem.Start + ")");

                        // the property does not exist... this mean that google calendar
                        // does not have this outlook entry...  after this call, the outlook item
                        // and the google item should be tied together by the use of properties...
                        gitem = GoogleCalendar.Instance.addEntry(oitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked);

                        // updated the stats
                        ++google_entries_added;
                    }
                }
                else
                {
                    // the property exists, so we need to determine if the event should be updated
                    // first, find the event in the list of google items...
                    Event gitem = null;
                    foreach (var g in google_items)
                    {
                        if (oitem_google_prop.Value == g.Id)
                        {
                            gitem = g; break;
                        }
                    }

                    if (gitem == null)
                    {
                        // give some indication of what will take place
                        logboxout("Removing Outlook event: " + oitem.Subject + " (" + oitem.Start + ")");

                        // the item does not exist, so it was removed from google calendar
                        // since it was removed from google, remove it from outlook
                        OutlookCalendar.Instance.deleteCalendarEntry(oitem);

                        // outlook item can no longer be used after it is deleted
                        outlook_items.RemoveAt(i);

                        // need to release the com reference
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem);

                        // update the stats
                        ++outlook_entries_removed;
                    }
                    else
                    {
                        // the item does exist...
                        // determine if the event should be updated...
                        if ((signature(oitem) != signature(gitem) ||
                             OutlookGoogleSync.Utilities.ObtainUserBodyData(oitem.Body) != OutlookGoogleSync.Utilities.ObtainUserBodyData(gitem.Description)) &&
                            oitem.LastModificationTime > gitem.Updated)
                        {
                            // the google event can only be updated if owned by the calendar...
                            if (gitem.Organizer.Self.HasValue && gitem.Organizer.Self.Value)
                            {
                                // give some indication of what will take place
                                if (signature(oitem) != signature(gitem))
                                {
                                    logboxout("Updating Google event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ") ==> " + oitem.Subject + " (" + oitem.Start + ")");
                                }
                                else
                                {
                                    logboxout("Updating Google event description: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")");
                                }

                                // update the event based on the outlook item
                                GoogleCalendar.Instance.updateEntry(gitem, oitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked);

                                // update the status
                                ++google_entries_updated;
                            }

                            // this google item has been processed
                            google_items.Remove(gitem);
                        }
                    }

                    // need to release the com reference
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem_google_prop);
                }
            }

            // second synchronize google -> outlook

            // run over all the google items and add or update on outlook
            for (int i = google_items.Count - 1; i >= 0; --i)
            {
                // obtain a reference to the google item...
                var gitem = google_items[i];

                // determine first if this google item is associated with an outlook calendar item...
                string outlook_id = null;
                if (gitem.ExtendedProperties != null &&
                    gitem.ExtendedProperties.Shared != null &&
                    gitem.ExtendedProperties.Shared.ContainsKey(EventPropertyKey))
                {
                    outlook_id = gitem.ExtendedProperties.Shared[EventPropertyKey];
                }

                if (outlook_id == null)
                {
                    // run across the outlook events to see if there is one that matches...
                    // this may not need to be done, as the google pass should have found them all...
                    // lets be on the safe side here and do it anyway...
                    AppointmentItem oitem = null;
                    foreach (var o in outlook_items)
                    {
                        // lowercase match the signature and
                        // the property is not set or the property matches the gitem, match found...
                        // the user has to type it the same in both cases to make a match...
                        // is there something better here?
                        if (signature(o).ToLower() == signature(gitem).ToLower() &&
                            (o.UserProperties == null ||
                             o.UserProperties.Find(EventPropertyKey) == null ||
                             o.UserProperties.Find(EventPropertyKey).Value == gitem.Id))
                        {
                            oitem = o; break;
                        }
                    }

                    if (oitem != null)
                    {
                        // give some indication of what will take place
                        logboxout("Binding Outlook and Google event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")");

                        // bind the properties together
                        OutlookCalendar.Instance.Bind(oitem, gitem);

                        // update the instance on the google calendar
                        GoogleCalendar.Instance.updateEntry(gitem);

                        // remove the outlook item and the google item from the lists...
                        // do not need to process them again for future iterations...
                        google_items.Remove(gitem);
                        outlook_items.Remove(oitem);

                        // save and close the outlook item
                        ((_AppointmentItem)oitem).Close(OlInspectorClose.olSave);

                        // need to release the com reference
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem);

                        // update the stats
                        ++bound_entries_found;
                    }
                    else
                    {
                        // give some indication of what will take place
                        logboxout("Creating Outlook event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")");

                        // the property does not exist... this means that the outlook calendar
                        // does not have this google entry...  after this call, the outlook item
                        // and the google item should be tied together by the use of properties...
                        oitem = OutlookCalendar.Instance.addEntry(gitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked);

                        try
                        {
                            // google currently does not have an updated id... this needs to be reflected on the server...
                            GoogleCalendar.Instance.updateEntry(gitem);
                        }
                        catch (System.Exception ex)
                        {
                            // unable to update the google entry for some reason...
                            // let the user know and the reason why...
                            logboxout("");
                            logboxout("Error: Google event cannot be bound to Outlook event!");
                            logboxout("Reason: " + ex.Message);
                            logboxout("");

                            // update the stats
                            ++errors;
                        }

                        // need to release the com reference
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem);

                        // update the stats
                        ++outlook_entries_added;
                    }
                }
                else
                {
                    // the property exists, so we need to determine if the event should be updated
                    // first, find the event in the list of outlook items...
                    AppointmentItem oitem = null;
                    foreach (var o in outlook_items)
                    {
                        if (outlook_id == OutlookCalendar.FormatEventID(o))
                        {
                            oitem = o; break;
                        }
                    }

                    if (oitem == null)
                    {
                        // give some indication of what will take place
                        logboxout("Removing Google event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")");

                        // the item does not exist, so it was removed from outlook calendar
                        // since it was removed from outlook, remove it from google
                        GoogleCalendar.Instance.deleteCalendarEntry(gitem);

                        // update the stats
                        ++google_entries_removed;
                    }
                    else
                    {
                        // this outlook item is about to be processed... no matter the action
                        // taken, we can remove it from the list of items, so as not
                        // to need to look at it again in future iterations...
                        outlook_items.Remove(oitem);

                        // the item does exist...
                        // determine if the event should be updated...
                        if ((signature(gitem) != signature(oitem) ||
                             OutlookGoogleSync.Utilities.ObtainUserBodyData(oitem.Body) != OutlookGoogleSync.Utilities.ObtainUserBodyData(gitem.Description)) &&
                            gitem.Updated > oitem.LastModificationTime)
                        {
                            // give some indication of what will take place
                            if (signature(gitem) != signature(oitem))
                            {
                                logboxout("Updating Outlook event: " + oitem.Subject + " (" + oitem.Start + ") ==> " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")");
                            }
                            else
                            {
                                logboxout("Updating Outlook event description: " + oitem.Subject + " (" + oitem.Start + ")");
                            }

                            // update the event based on the google item
                            OutlookCalendar.Instance.updateEntry(oitem, gitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked);

                            // update the status
                            ++outlook_entries_updated;
                        }

                        try
                        {
                            // save and close the outlook item
                            ((_AppointmentItem)oitem).Close(OlInspectorClose.olSave);
                        }
                        catch (System.Exception ex)
                        {
                            // unable to save the outlook entry for some reason...
                            // let the user know and the reason why...
                            logboxout("");
                            logboxout("Error: Outlook event cannot be saved!");
                            logboxout("Reason: " + ex.Message);
                            logboxout("");

                            // update the stats
                            ++errors;
                        }

                        // need to release the com reference
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem);
                    }
                }
            }

            // close all the outlook items
            foreach (var o in outlook_items)
            {
                ((_AppointmentItem)o).Close(OlInspectorClose.olSave);

                System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
            }

            // clear out both lists... these items have been processed...
            outlook_items.Clear();
            google_items.Clear();

            // summarize the changes made
            logboxout("--------------------------------------------------");
            logboxout("Google entries added: " + google_entries_added);
            logboxout("Google entries updated: " + google_entries_updated);
            logboxout("Google entries removed: " + google_entries_removed);
            logboxout("");
            logboxout("Outlook entries added: " + outlook_entries_added);
            logboxout("Outlook entries updated: " + outlook_entries_updated);
            logboxout("Outlook entries removed: " + outlook_entries_removed);
            logboxout("");
            logboxout("Bound entries found: " + bound_entries_found);
            logboxout("");
            logboxout("Errors found: " + errors);

            return(errors == 0);
        }
        private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (e.Argument is string &&
                "DELETE".Equals((string)e.Argument))
            {
                deleteAllSyncItems();
                return;
            }

            AppointmentItemCache appointmentItemCache = new AppointmentItemCache();
            EventCache           eventCache           = new EventCache();

            DateTime        syncStarted = DateTime.Now;
            OutlookCalendar ocal        = null;

            try
            {
                logboxout("Sync started at " + syncStarted.ToString());
                logboxout("--------------------------------------------------");

                logboxout("Reading Outlook Calendar Entries...");
                ocal = new OutlookCalendar();
                List <AppointmentItemCacheEntry> OutlookEntries = new List <AppointmentItemCacheEntry>();
                foreach (AppointmentItem a in ocal.getCalendarEntriesInRange(syncStarted))
                {
                    OutlookEntries.Add(appointmentItemCache.GetAppointmentItemCacheEntry(a, ocal.AccountName));
                }

                if (checkBoxCreateFiles.Checked)
                {
                    using (TextWriter tw = new StreamWriter("export_found_in_outlook.txt"))
                    {
                        foreach (AppointmentItemCacheEntry ai in OutlookEntries)
                        {
                            tw.WriteLine(ai.Signature);
                        }
                    }
                }

                logboxout("Found " + OutlookEntries.Count + " Outlook Calendar Entries.");
                logboxout("--------------------------------------------------");
                logboxout("Reading Google Calendar Entries...");

                string accountName = "(Empty)";
                if (ocal != null || !string.IsNullOrEmpty(ocal.AccountName))
                {
                    accountName = ocal.AccountName;
                }

                GoogleCalendar         gcal          = new GoogleCalendar();
                List <EventCacheEntry> GoogleEntries = new List <EventCacheEntry>();
                foreach (Event ev in gcal.getCalendarEntriesInRange(syncStarted))
                {
                    GoogleEntries.Add(eventCache.GetEventCacheEntry(ev, accountName));
                }

                if (checkBoxCreateFiles.Checked)
                {
                    using (TextWriter tw = new StreamWriter("export_found_in_google.txt"))
                    {
                        foreach (EventCacheEntry ev in GoogleEntries)
                        {
                            tw.WriteLine(ev.Signature);
                        }
                    }
                }

                logboxout("Found " + GoogleEntries.Count + " Google Calendar Entries.");
                logboxout("--------------------------------------------------");

                List <EventCacheEntry> GoogleEntriesToBeDeleted = identifyGoogleEntriesToBeDeleted(OutlookEntries, GoogleEntries, accountName);
                if (checkBoxCreateFiles.Checked)
                {
                    using (TextWriter tw = new StreamWriter("export_to_be_deleted.txt"))
                    {
                        foreach (EventCacheEntry ev in GoogleEntriesToBeDeleted)
                        {
                            tw.WriteLine(ev.Signature);
                        }
                    }
                }

                logboxout(GoogleEntriesToBeDeleted.Count + " Google Calendar Entries to be deleted.");

                //OutlookEntriesToBeCreated ...in Google!
                List <AppointmentItemCacheEntry> OutlookEntriesToBeCreated = identifyOutlookEntriesToBeCreated(OutlookEntries, GoogleEntries);
                if (checkBoxCreateFiles.Checked)
                {
                    using (TextWriter tw = new StreamWriter("export_to_be_created.txt"))
                    {
                        foreach (AppointmentItemCacheEntry ai in OutlookEntriesToBeCreated)
                        {
                            tw.WriteLine(ai.Signature);
                        }
                    }
                }

                logboxout(OutlookEntriesToBeCreated.Count + " Entries to be created in Google.");
                logboxout("--------------------------------------------------");

                if (GoogleEntriesToBeDeleted.Count > 0)
                {
                    logboxout("Deleting " + GoogleEntriesToBeDeleted.Count + " Google Calendar Entries...");
                    foreach (EventCacheEntry ev in GoogleEntriesToBeDeleted)
                    {
                        gcal.deleteCalendarEntry(ev.Event);
                    }
                    logboxout("Done.");
                    logboxout("--------------------------------------------------");
                }

                if (OutlookEntriesToBeCreated.Count > 0)
                {
                    logboxout("Creating " + OutlookEntriesToBeCreated.Count + " Entries in Google...");
                    foreach (AppointmentItemCacheEntry aice in OutlookEntriesToBeCreated)
                    {
                        AppointmentItem ai = aice.AppointmentItem;
                        Event           ev = new Event();

                        ev.Start = new EventDateTime();
                        ev.End   = new EventDateTime();

                        if (ai.AllDayEvent)
                        {
                            ev.Start.Date = ai.Start.ToString("yyyy-MM-dd");
                            ev.End.Date   = ai.End.ToString("yyyy-MM-dd");
                        }
                        else
                        {
                            ev.Start.DateTime = GoogleCalendar.GoogleTimeFrom(ai.Start);
                            ev.End.DateTime   = GoogleCalendar.GoogleTimeFrom(ai.End);
                        }

                        ev.Summary = ai.Subject;
                        if (checkBoxAddDescription.Checked)
                        {
                            try
                            {
                                ev.Description = ai.Body;
                            }
                            catch (System.Exception ex)
                            {
                                string startDt = ai.AllDayEvent ? ai.Start.ToShortDateString() : ai.Start.ToString();
                                string endDt   = ai.AllDayEvent ? ai.End.ToShortDateString() : ai.End.ToString();
                                logboxout("Error accessing the body of Outlook item. Body will be empty.\r\n    Subject: [" + ev.Summary + "]\r\n    Start: [" + startDt + "]\r\n    End: [" + endDt + "]\r\n    Error: " + ex.Message);
                            }
                        }

                        ev.Location = ai.Location;

                        //consider the reminder set in Outlook
                        if (checkBoxAddReminders.Checked && ai.ReminderSet)
                        {
                            ev.Reminders            = new Event.RemindersData();
                            ev.Reminders.UseDefault = false;
                            EventReminder reminder = new EventReminder();
                            reminder.Method        = "popup";
                            reminder.Minutes       = ai.ReminderMinutesBeforeStart;
                            ev.Reminders.Overrides = new List <EventReminder>();
                            ev.Reminders.Overrides.Add(reminder);
                        }
                        else
                        {
                            ev.Reminders            = new Event.RemindersData();
                            ev.Reminders.UseDefault = false;
                        }

                        if (checkBoxAddAttendees.Checked)
                        {
                            ev.Description += Environment.NewLine;
                            ev.Description += Environment.NewLine + "==============================================";
                            ev.Description += Environment.NewLine + "Added by OutlookGoogleSync (" + accountName + "):" + Environment.NewLine;
                            ev.Description += Environment.NewLine + "ORGANIZER: " + Environment.NewLine + ai.Organizer + Environment.NewLine;
                            ev.Description += Environment.NewLine + "REQUIRED: " + Environment.NewLine + splitAttendees(ai.RequiredAttendees) + Environment.NewLine;
                            if (ai.OptionalAttendees != null)
                            {
                                ev.Description += Environment.NewLine + "OPTIONAL: " + Environment.NewLine + splitAttendees(ai.OptionalAttendees);
                            }

                            ev.Description += Environment.NewLine + "==============================================";
                        }

                        gcal.addEntry(ev);
                    }

                    logboxout("Done.");
                    logboxout("--------------------------------------------------");
                }

                DateTime syncFinished = DateTime.Now;
                TimeSpan elapsed      = syncFinished - syncStarted;
                logboxout("Sync finished at " + syncFinished.ToString());
                logboxout("Time needed: " + elapsed.Minutes + " min " + elapsed.Seconds + " s");
            }
            catch (System.Exception ex)
            {
                logboxout("Error Syncing:\r\n" + ex.ToString());
            }

            eventCache.Clear();
            freeCOMResources(ocal, appointmentItemCache);
        }