/// <summary>
        /// Get the existing sync state for this item, if it exists and is of the appropriate
        /// type, else null.
        /// </summary>
        /// <remarks>Outlook items are not true objects and don't have a common superclass,
        /// so we have to use this rather clumsy overloading.</remarks>
        /// <param name="task">The item.</param>
        /// <returns>The appropriate sync state, or null if none.</returns>
        /// <exception cref="UnexpectedSyncStateClassException">if the sync state found is not of the expected class (shouldn't happen).</exception>
        public TaskSyncState GetSyncState(Outlook.TaskItem task)
        {
            SyncState result;

            try
            {
                result = this.byOutlookId.ContainsKey(task.EntryID) ? this.byOutlookId[task.EntryID] : null;
                CrmId crmId = result == null?task.GetCrmId() : CheckForDuplicateSyncState(result, task.GetCrmId());

                if (CrmId.IsValid(crmId))
                {
                    if (result == null && this.byCrmId.ContainsKey(crmId))
                    {
                        result = this.byCrmId[crmId];
                    }
                    else if (result != null && crmId != null && this.byCrmId.ContainsKey(crmId) == false)
                    {
                        this.byCrmId[crmId] = result;
                        result.CrmEntryId   = crmId;
                    }
                }

                if (result != null && !(result is TaskSyncState))
                {
                    throw new UnexpectedSyncStateClassException("TaskSyncState", result);
                }
            }
            catch (COMException)
            {
                // dead item passed.
                result = null;
            }

            return(result as TaskSyncState);
        }
        /// <summary>
        /// Log a message regarding this Outlook item, with detail of the item.
        /// </summary>
        /// <param name="olItem">The outlook item.</param>
        /// <param name="message">The message to be logged.</param>
        internal override void LogItemAction(Outlook.ContactItem olItem, string message)
        {
            if (olItem != null && olItem.IsValid())
            {
                try
                {
                    CrmId crmId = this.IsEnabled() ? olItem.GetCrmId() : CrmId.Empty;
                    if (CrmId.IsInvalid(crmId))
                    {
                        crmId = CrmId.Empty;
                    }

                    StringBuilder bob = new StringBuilder();
                    bob.Append($"{message}:\n\tOutlook Id  : {olItem.EntryID}")
                    .Append(this.IsEnabled() ? $"\n\tCRM Id      : {crmId}" : string.Empty)
                    .Append($"\n\tFull name   : '{olItem.FullName}'")
                    .Append($"\n\tSensitivity : {olItem.Sensitivity}")
                    .Append($"\n\tTxState     : {SyncStateManager.Instance.GetExistingSyncState(olItem)?.TxState}");

                    Log.Info(bob.ToString());
                }
                catch (COMException)
                {
                    // Ignore: happens if the outlook item is already deleted.
                }
            }
        }
Beispiel #3
0
        private bool TryAddRecipientInModule(string moduleName, CrmId meetingId, Outlook.Recipient recipient)
        {
            bool  result;
            CrmId id = SetCrmRelationshipFromOutlook(this, meetingId, recipient, moduleName);

            if (CrmId.IsValid(id))
            {
                string smtpAddress = recipient.GetSmtpAddress();

                this.CacheAddressResolutionData(
                    new AddressResolutionData(moduleName, id, smtpAddress));

                CrmId accountId = CrmId.Get(RestAPIWrapper.GetRelationship(
                                                ContactSynchroniser.CrmModule, id.ToString(), "accounts"));

                if (CrmId.IsValid(accountId) &&
                    SetCrmRelationshipFromOutlook(this, meetingId, "Accounts", accountId))
                {
                    this.CacheAddressResolutionData(
                        new AddressResolutionData("Accounts", accountId, smtpAddress));
                }

                result = true;
            }
            else
            {
                result = false;
            }

            return(result);
        }
        /// <summary>
        /// Get the existing sync state for this CRM item, if it exists, else null.
        /// </summary>
        /// <param name="outlookId">The Outlook id of the syncstate to seek.</param>
        /// <param name="crmId">The CRM id of the syncstate to seek.</param>
        /// <returns>The appropriate sync state, or null if none.</returns>
        public SyncState GetExistingSyncState(string outlookId, CrmId crmId)
        {
            SyncState result;

            if (this.byCrmId.ContainsKey(crmId))
            {
                result = this.byCrmId[crmId];
            }
            else if (!string.IsNullOrEmpty(outlookId))
            {
                if (this.byOutlookId.ContainsKey(outlookId))
                {
                    result = this.byOutlookId[outlookId];
                }
                else
                {
                    result = this.byGlobalId.ContainsKey(outlookId) ?
                             this.byGlobalId[outlookId] :
                             null;
                }
            }
            else
            {
                string simulatedGlobalId = SyncStateManager.SimulateGlobalId(crmId);

                result = this.byGlobalId.ContainsKey(simulatedGlobalId) ? this.byGlobalId[simulatedGlobalId] : null;
            }

            return(result);
        }
        /// <summary>
        /// Get the existing sync state for this item, if it exists and is of the appropriate
        /// type, else null.
        /// </summary>
        /// <remarks>Outlook items are not true objects and don't have a common superclass,
        /// so we have to use this rather clumsy overloading.</remarks>
        /// <param name="contact">The item.</param>
        /// <returns>The appropriate sync state, or null if none.</returns>
        /// <exception cref="UnexpectedSyncStateClassException">if the sync state found is not of the expected class (shouldn't happen).</exception>
        public ContactSyncState GetSyncState(Outlook.ContactItem contact)
        {
            SyncState result;

            try
            {
                result = this.byOutlookId.ContainsKey(contact.EntryID) ? this.byOutlookId[contact.EntryID] : null;
                CrmId crmId = CheckForDuplicateSyncState(result, contact.GetCrmId());

                if (CrmId.IsValid(crmId))
                {
                    if (result == null && this.byCrmId.ContainsKey(crmId))
                    {
                        result = this.byCrmId[crmId];
                    }
                    else if (result != null && this.byCrmId.ContainsKey(crmId) == false)
                    {
                        this.byCrmId[crmId] = result;
                        result.CrmEntryId   = crmId;
                    }
                }

                if (result != null && result as ContactSyncState == null)
                {
                    throw new UnexpectedSyncStateClassException("ContactSyncState", result);
                }
            }
            catch (COMException)
            {
                // dead item passed.
                result = null;
            }

            return(result as ContactSyncState);
        }
Beispiel #6
0
        /// <summary>
        /// Check meeting acceptances for all future meetings.
        /// </summary>
        private int CheckMeetingAcceptances()
        {
            int result = 0;

            foreach (MeetingSyncState state in SyncStateManager.Instance.GetSynchronisedItems <MeetingSyncState>().Where(s => s.VerifyItem()))
            {
                Outlook.AppointmentItem item = state.OutlookItem;

                try
                {
                    if (CrmId.Get(item.UserProperties[OrganiserPropertyName]?.Value)
                        .Equals(RestAPIWrapper.GetUserId()) &&
                        item.Start > DateTime.Now)
                    {
                        result += AddOrUpdateMeetingAcceptanceFromOutlookToCRM(item);
                    }
                }
                catch (TypeInitializationException tix)
                {
                    Log.Warn("Failed to create CrmId with value '{item.UserProperties[OrganiserPropertyName]?.Value}'", tix);
                }
                catch (COMException comx)
                {
                    ErrorHandler.Handle($"Item with CRMid {state.CrmEntryId} appears to be invalid (HResult {comx.HResult})", comx);
                    this.HandleItemMissingFromOutlook(state);
                }
            }

            return(result);
        }
        /// <summary>
        /// Create an appropriate sync state for an appointment item.
        /// </summary>
        /// <remarks>Outlook items are not true objects and don't have a common superclass,
        /// so we have to use this rather clumsy overloading.</remarks>
        /// <param name="appointment">The item.</param>
        /// <returns>An appropriate sync state, or null if the appointment was invalid.</returns>
        private AppointmentSyncState CreateSyncState(Outlook.AppointmentItem appointment)
        {
            AppointmentSyncState result;

            CrmId crmId = appointment.GetCrmId();

            if (CrmId.IsValid(crmId) && this.byCrmId.ContainsKey(crmId) && this.byCrmId[crmId] != null)
            {
                result = CheckUnexpectedFoundState <Outlook.AppointmentItem, AppointmentSyncState>(appointment, crmId);
            }
            else
            {
                var modifiedDate = ParseDateTimeFromUserProperty(appointment.UserProperties[ModifiedDatePropertyName]);
                if (appointment.IsCall())
                {
                    result = this.SetByOutlookId <AppointmentSyncState>(appointment.EntryID,
                                                                        new CallSyncState(appointment, crmId, modifiedDate));
                }
                else
                {
                    result = this.SetByOutlookId <AppointmentSyncState>(appointment.EntryID,
                                                                        new MeetingSyncState(appointment, crmId, modifiedDate));
                }
                this.byGlobalId[appointment.GlobalAppointmentID] = result;
            }

            if (result != null && CrmId.IsValid(crmId))
            {
                this.byCrmId[crmId] = result;
            }

            return(result);
        }
        /// <summary>
        /// Get the existing sync state for this item, if it exists and is of the appropriate
        /// type, else null.
        /// </summary>
        /// <remarks>Outlook items are not true objects and don't have a common superclass,
        /// so we have to use this rather clumsy overloading.</remarks>
        /// <param name="appointment">The item.</param>
        /// <returns>The appropriate sync state, or null if none.</returns>
        /// <exception cref="UnexpectedSyncStateClassException">if the sync state found is not of the expected class (shouldn't happen).</exception>
        public AppointmentSyncState GetSyncState(Outlook.AppointmentItem appointment)
        {
            SyncState result;

            try
            {
                result = (appointment.IsValid() && this.byOutlookId.ContainsKey(appointment.EntryID)) ? this.byOutlookId[appointment.EntryID] : null;
                CrmId crmId = result == null?appointment.GetCrmId() : CheckForDuplicateSyncState(result, appointment.GetCrmId());

                if (CrmId.IsValid(crmId))
                {
                    if (result == null && this.byCrmId.ContainsKey(crmId))
                    {
                        result = this.byCrmId[crmId];
                    }
                    else if (result != null && this.byCrmId.ContainsKey(crmId) == false)
                    {
                        this.byCrmId[crmId] = result;
                        result.CrmEntryId   = crmId;
                    }
                }

                if (result != null && !(result is AppointmentSyncState))
                {
                    throw new UnexpectedSyncStateClassException("AppointmentSyncState", result);
                }
            }
            catch (COMException)
            {
                // dead item passed.
                result = null;
            }

            return(result as AppointmentSyncState);
        }
Beispiel #9
0
        /// <summary>
        /// Find all CRM records related to this recipient of this meeting, and produce address
        /// resolution data from them.
        /// </summary>
        /// <param name="olItem">An appointment, assumed to be a meeting.</param>
        /// <param name="recipient">A recipient of that meeting request.</param>
        /// <returns>A list of address resolution objects.</returns>
        private List <AddressResolutionData> ResolveRecipient(Outlook.AppointmentItem olItem, Outlook.Recipient recipient)
        {
            List <AddressResolutionData> result = new List <AddressResolutionData>();
            var smtpAddress = recipient.GetSmtpAddress();

            Log.Info($"recepientName= {recipient.Name}, recepient= {smtpAddress}");

            if (this.meetingRecipientsCache.ContainsKey(smtpAddress))
            {
                result.AddRange(meetingRecipientsCache[smtpAddress]);
            }
            else
            {
                CrmId meetingId = olItem.GetCrmId();
                Dictionary <string, CrmId> moduleIds = new Dictionary <string, CrmId>();

                if (CrmId.IsValid(meetingId))
                {
                    foreach (string moduleName in new string[] { "Leads", "Users", ContactSynchroniser.CrmModule })
                    {
                        CrmId moduleId = this.GetInviteeIdBySmtpAddress(smtpAddress, moduleName);
                        if (CrmId.IsValid(moduleId))
                        {
                            moduleIds[moduleName] = moduleId;
                            AddressResolutionData data = new AddressResolutionData(moduleName, moduleId, smtpAddress);
                            this.CacheAddressResolutionData(data);
                            result.Add(data);
                        }
                    }

                    if (moduleIds.ContainsKey(ContactSynchroniser.CrmModule))
                    {
                        CrmId accountId = CrmId.Get(RestAPIWrapper.GetRelationship(
                                                        ContactSynchroniser.CrmModule,
                                                        moduleIds[ContactSynchroniser.CrmModule].ToString(),
                                                        "accounts"));

                        if (CrmId.IsValid(accountId) &&
                            SetCrmRelationshipFromOutlook(this, meetingId, "Accounts", accountId))
                        {
                            var data = new AddressResolutionData("Accounts", accountId, smtpAddress);
                            this.CacheAddressResolutionData(data);
                            result.Add(data);
                        }
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Called after a new item has been created from a CRM item, to fix up the index and prevent duplication.
        /// </summary>
        /// <typeparam name="SyncStateType">The type of <see cref="SyncState"/> passed</typeparam>
        /// <param name="crmId">The crmId to index this sync state to.</param>
        /// <param name="syncState">the sync state to index.</param>
        internal void SetByCrmId <SyncStateType>(CrmId crmId, SyncStateType syncState) where SyncStateType : SyncState
        {
            if (this.byCrmId.ContainsKey(crmId) && this.byCrmId[crmId] != null && this.byCrmId[crmId] != syncState)
            {
                throw new DuplicateCrmIdException(syncState, crmId);
            }

            this.byCrmId[crmId] = syncState;
            string outlookId = syncState?.OutlookItemEntryId;

            if (!string.IsNullOrEmpty(outlookId))
            {
                this.byOutlookId[outlookId] = syncState;
            }
        }
Beispiel #11
0
 /// <summary>
 /// If it was created in Outlook and doesn't exist in CRM,  (in which case it won't yet have a
 /// magic SShouldSync property) then we need to guarantee changes made in CRM are copied back
 /// by setting the Sync to Outlook checkbox in CRM.
 /// </summary>
 /// <param name="contactIdInCRM">The identifier of the contact in the CRM system</param>
 /// <param name="syncProperty">If null, set the checkbox.</param>
 /// <param name="create">If provided and false, then remove rather than creating the relationship.</param>
 private static void EnsureSyncWithOutlookSetInCRM(CrmId contactIdInCRM, Outlook.UserProperty syncProperty, bool create = true)
 {
     if (syncProperty == null)
     {
         SetRelationshipParams info = new SetRelationshipParams
         {
             module1    = CrmModule,
             module1_id = contactIdInCRM.ToString(),
             module2    = "user_sync",
             module2_id = RestAPIWrapper.GetUserId(),
             delete     = create ? 0 : 1
         };
         RestAPIWrapper.SetRelationshipUnsafe(info);
     }
 }
        public void CreateEmailRelationshipOrFail(CrmId emailId, CrmEntity entity)
        {
            var success = RestAPIWrapper.TrySetRelationship(
                new SetRelationshipParams
            {
                module2    = "emails",
                module2_id = emailId.ToString(),
                module1    = entity.ModuleName,
                module1_id = entity.EntityId,
            }, Objective.Email);

            if (!success)
            {
                throw new CrmSaveDataException($"Cannot create email relationship with {entity.ModuleName} ('set_relationship' failed)");
            }
        }
        /// <summary>
        /// Check whether there exists a sync state other than this state whose CRM id is
        /// this CRM id or the CRM id of this state.
        /// </summary>
        /// <param name="state">The sync state to be checked.</param>
        /// <param name="crmId">A candidate CRM id.</param>
        /// <returns>A better guess at the CRM id.</returns>
        /// <exception cref="DuplicateSyncStateException">If a duplicate is detected.</exception>
        private CrmId CheckForDuplicateSyncState(SyncState state, CrmId crmId)
        {
            CrmId result = CrmId.IsInvalid(crmId) && state != null ? state.CrmEntryId : crmId;

            if (result != null)
            {
                SyncState byCrmState = this.byCrmId.ContainsKey(crmId) ? this.byCrmId[crmId] : null;

                if (state != null && byCrmState != null && state != byCrmState)
                {
                    throw new DuplicateSyncStateException(state);
                }
            }

            return(result);
        }
        /// <summary>
        /// Get the existing sync state for this CRM item, if it exists, else null.
        /// </summary>
        /// <param name="crmItem">The item.</param>
        /// <returns>The appropriate sync state, or null if none.</returns>
        public SyncState GetExistingSyncState(EntryValue crmItem)
        {
            SyncState result;
            string    outlookId = crmItem.GetValueAsString("outlook_id");
            CrmId     crmId     = CrmId.Get(crmItem.id);

            if (this.byCrmId.ContainsKey(crmId))
            {
                result = this.byCrmId[crmId];
            }
            else if (this.byOutlookId.ContainsKey(outlookId))
            {
                result = this.byOutlookId[outlookId];
            }
            else if (this.byGlobalId.ContainsKey(outlookId))
            {
                result = this.byGlobalId[outlookId];
            }
            else
            {
                string simulatedGlobalId = SyncStateManager.SimulateGlobalId(crmId);

                if (this.byGlobalId.ContainsKey(simulatedGlobalId))
                {
                    result = this.byGlobalId[simulatedGlobalId];
                }
                else
                {
                    string distinctFields = GetDistinctFields(crmItem);

                    if (string.IsNullOrEmpty(distinctFields))
                    {
                        result = null;
                    }
                    else if (this.byDistinctFields.ContainsKey(distinctFields))
                    {
                        result = this.byDistinctFields[distinctFields];
                    }
                    else
                    {
                        result = null;
                    }
                }
            }

            return(result);
        }
Beispiel #15
0
        /// <summary>
        /// Add the Outlook item referenced by this sync state, which may not exist in CRM, to CRM.
        /// </summary>
        /// <param name="syncState">The sync state referencing the outlook item to add.</param>
        /// an update, not an add).</param>
        /// <returns>The id of the entry added o</returns>
        internal override CrmId AddOrUpdateItemFromOutlookToCrm(SyncState <Outlook.ContactItem> syncState)
        {
            CrmId result = CrmId.Empty;
            var   olItem = syncState.OutlookItem;

            if (this.ShouldAddOrUpdateItemFromOutlookToCrm(olItem))
            {
                result = base.AddOrUpdateItemFromOutlookToCrm(syncState);

                Outlook.UserProperty syncProperty = olItem.UserProperties["SShouldSync"];
                string shouldSync = syncProperty == null?
                                    Boolean.TrueString.ToLower() :
                                        syncProperty.Value;

                EnsureSyncWithOutlookSetInCRM(result, syncProperty);
            }

            return(result);
        }
Beispiel #16
0
        /// <summary>
        /// Set all those properties of this outlook item whose values are different from the
        /// equivalent values on this CRM item. Update the synchronisation properties only if some
        /// other property has actually changed.
        /// </summary>
        /// <param name="crmItem">The CRM item from which to take values.</param>
        /// <param name="olItem">The Outlook item into which to insert values.</param>
        /// <returns>true if anything was changed.</returns>
        private void SetOutlookItemPropertiesFromCrmItem(EntryValue crmItem, Outlook.ContactItem olItem)
        {
            try
            {
                olItem.FirstName                 = crmItem.GetValueAsString("first_name");
                olItem.LastName                  = crmItem.GetValueAsString("last_name");
                olItem.Email1Address             = crmItem.GetValueAsString("email1");
                olItem.BusinessTelephoneNumber   = crmItem.GetValueAsString("phone_work");
                olItem.HomeTelephoneNumber       = crmItem.GetValueAsString("phone_home");
                olItem.MobileTelephoneNumber     = crmItem.GetValueAsString("phone_mobile");
                olItem.JobTitle                  = crmItem.GetValueAsString("title");
                olItem.Department                = crmItem.GetValueAsString("department");
                olItem.BusinessAddressCity       = crmItem.GetValueAsString("primary_address_city");
                olItem.BusinessAddressCountry    = crmItem.GetValueAsString("primary_address_country");
                olItem.BusinessAddressPostalCode = crmItem.GetValueAsString("primary_address_postalcode");
                olItem.BusinessAddressState      = crmItem.GetValueAsString("primary_address_state");
                olItem.BusinessAddressStreet     = crmItem.GetValueAsString("primary_address_street");
                olItem.Body = crmItem.GetValueAsString("description");
                if (crmItem.GetValue("account_name") != null)
                {
                    olItem.Account     = crmItem.GetValueAsString("account_name");
                    olItem.CompanyName = crmItem.GetValueAsString("account_name");
                }
                olItem.BusinessFaxNumber = crmItem.GetValueAsString("phone_fax");
                olItem.Title             = crmItem.GetValueAsString("salutation");

                if (olItem.Sensitivity != Outlook.OlSensitivity.olNormal)
                {
                    Log.Info($"ContactSyncing.SetOutlookItemPropertiesFromCrmItem: setting sensitivity of contact {crmItem.GetValueAsString("first_name")} {crmItem.GetValueAsString("last_name")} ({crmItem.GetValueAsString("email1")}) to normal");
                    olItem.Sensitivity = Outlook.OlSensitivity.olNormal;
                }

                EnsureSynchronisationPropertiesForOutlookItem(
                    olItem,
                    crmItem.GetValueAsString("date_modified"),
                    crmItem.GetValueAsString("sync_contact"),
                    CrmId.Get(crmItem.id));
            }
            finally
            {
                this.SaveItem(olItem);
            }
        }
        /// <summary>
        ///     Get the single CrmId instance for this value.
        /// </summary>
        /// <param name="value">The value to seek.</param>
        /// <returns>A CrmId instance, or Empty if the offered value is invalid.</returns>
        public static CrmId Get(string value)
        {
            CrmId result = Empty;

            if (IsValid(value))
            {
                if (Issued.ContainsKey(value))
                {
                    result = Issued[value];
                }
                else
                {
                    result = new CrmId(value);
                }
            }
            // This breaks, and I can't understand why:
            // return IsValid(value) ? Empty : Issued.ContainsKey(value) ? Issued[value] : new CrmId(value);

            return(result);
        }
Beispiel #18
0
        internal override CrmId AddOrUpdateItemFromOutlookToCrm(SyncState <Outlook.AppointmentItem> syncState)
        {
            CrmId previousCrmId = syncState.CrmEntryId;
            CrmId result        = base.AddOrUpdateItemFromOutlookToCrm(syncState);

            if (CrmId.IsValid(result))
            {
                if (CrmId.IsInvalid(previousCrmId)) /* i.e., it's new */
                {
                    if (syncState.OutlookItem.Recipients != null)
                    {
                        AddMeetingRecipientsFromOutlookToCrm(syncState.OutlookItem, result);
                    }

                    this.AddOrUpdateMeetingAcceptanceFromOutlookToCRM(syncState.OutlookItem);
                }
            }

            return(result);
        }
        /// <summary>
        /// Create an appropriate sync state for an contact item.
        /// </summary>
        /// <remarks>Outlook items are not true objects and don't have a common superclass,
        /// so we have to use this rather clumsy overloading.</remarks>
        /// <param name="contact">The item.</param>
        /// <returns>An appropriate sync state.</returns>
        private ContactSyncState CreateSyncState(Outlook.ContactItem contact)
        {
            CrmId            crmId = contact.GetCrmId();
            ContactSyncState result;

            if (CrmId.IsValid(crmId) && this.byCrmId.ContainsKey(crmId) && this.byCrmId[crmId] != null)
            {
                result = CheckUnexpectedFoundState <Outlook.ContactItem, ContactSyncState>(contact, crmId);
            }
            else
            {
                result = this.SetByOutlookId <ContactSyncState>(contact.EntryID,
                                                                new ContactSyncState(contact, crmId,
                                                                                     ParseDateTimeFromUserProperty(contact.UserProperties[ModifiedDatePropertyName])));
            }

            if (result != null && CrmId.IsValid(crmId))
            {
                this.byCrmId[crmId] = result;
            }

            return(result);
        }
Beispiel #20
0
        /// <summary>
        /// Log a message regarding this Outlook appointment.
        /// </summary>
        /// <param name="olItem">The outlook item.</param>
        /// <param name="message">The message to be logged.</param>
        internal override void LogItemAction(Outlook.TaskItem olItem, string message)
        {
            try
            {
                CrmId crmId = olItem.GetCrmId();
                if (CrmId.IsInvalid(crmId))
                {
                    crmId = CrmId.Empty;
                }

                StringBuilder bob = new StringBuilder();
                bob.Append($"{message}:\n\tOutlook Id  : {olItem.EntryID}")
                .Append($"\n\tCRM Id      : {crmId}")
                .Append($"\n\tSubject     : '{olItem.Subject}'")
                .Append($"\n\tStatus      : {olItem.Status}")
                .Append($"\n\tSensitivity : {olItem.Sensitivity}")
                .Append($"\n\tTxState     : {SyncStateManager.Instance.GetExistingSyncState(olItem)?.TxState}");
                Log.Info(bob.ToString());
            }
            catch (COMException)
            {
                // Ignore: happens if the outlook item is already deleted.
            }
        }
 /// <summary>
 /// Remove all references to this sync state, if I hold any.
 /// </summary>
 /// <param name="state">The state to remove.</param>
 internal void RemoveSyncState(SyncState state)
 {
     lock (this.creationLock)
     {
         SyncState ignore;
         try
         {
             if (this.byOutlookId[state.OutlookItemEntryId] == state)
             {
                 this.byOutlookId.TryRemove(state.OutlookItemEntryId, out ignore);
             }
         }
         catch (KeyNotFoundException) { }
         catch (COMException) { }
         try
         {
             if (CrmId.IsValid(state.CrmEntryId) && this.byCrmId[state.CrmEntryId] == state)
             {
                 this.byCrmId.TryRemove(state.CrmEntryId, out ignore);
             }
         }
         catch (KeyNotFoundException) { }
     }
 }
        /// <summary>
        /// Create an appropriate sync state for an task item.
        /// </summary>
        /// <remarks>Outlook items are not true objects and don't have a common superclass,
        /// so we have to use this rather clumsy overloading.</remarks>
        /// <param name="task">The item.</param>
        /// <returns>An appropriate sync state, or null if the task was invalid.</returns>
        private TaskSyncState CreateSyncState(Outlook.TaskItem task)
        {
            TaskSyncState result;

            CrmId crmId = task.GetCrmId();

            if (CrmId.IsValid(crmId) && this.byCrmId.ContainsKey(crmId) && this.byCrmId[crmId] != null)
            {
                result = CheckUnexpectedFoundState <Outlook.TaskItem, TaskSyncState>(task, crmId);
            }
            else
            {
                result = this.SetByOutlookId <TaskSyncState>(task.EntryID,
                                                             new TaskSyncState(task, crmId,
                                                                               ParseDateTimeFromUserProperty(task.UserProperties[ModifiedDatePropertyName])));
            }

            if (result != null && CrmId.IsValid(crmId))
            {
                this.byCrmId[crmId] = result;
            }

            return(result);
        }
 public SyncState(ItemType item, CrmId crmId, DateTime modifiedDate)
 {
     this.OutlookItem   = item;
     this.CrmEntryId    = crmId;
     this.OModifiedDate = modifiedDate;
 }
        /// <summary>
        /// Perform sanity checks on an unexpected sync state has been found where we expected
        /// to find none.
        /// </summary>
        /// <remarks>This probably shouldn't happen and perhaps ought to be flagged as a hard error
        /// anyway.</remarks>
        /// <typeparam name="ItemType">The type of Outlook item being considered.</typeparam>
        /// <typeparam name="StateType">The appropriate sync state class for that item.</typeparam>
        /// <param name="olItem">The Outlook item being considered.</param>
        /// <param name="crmId">The CRM id associated with that item.</param>
        /// <returns>An appropriate sync state</returns>
        /// <exception cref="Exception">If the sync state doesn't exactly match what we would expect.</exception>
        private StateType CheckUnexpectedFoundState <ItemType, StateType>(ItemType olItem, CrmId crmId)
            where ItemType : class
            where StateType : SyncState <ItemType>
        {
            StateType result;
            var       state = this.byCrmId.ContainsKey(crmId) ? this.byCrmId[crmId] : null;

            if (state != null)
            {
                result = state as StateType;

                if (result == null)
                {
                    throw new Exception($"Unexpected state type found: {state.GetType().Name}.");
                }
                else if (!result.OutlookItem.Equals(olItem))
                {
                    throw new ProbableDuplicateItemException <ItemType>(olItem, $"Probable duplicate Outlook item; crmId is {crmId}; identifying fields are {result.IdentifyingFields}");
                }
            }
            else
            {
                result = this.CreateSyncStateForItem(olItem) as StateType;
            }

            return(result);
        }
        /// <summary>
        /// Return the global appointment id corresponding to this crm id.
        /// </summary>
        /// <remarks>
        /// Outlook items arriving from CRM have a global appointment id based on their CRM id.
        /// Arguably this should not go here.
        /// </remarks>
        /// <see cref="Outlook.AppointmentItem.GlobalAppointmentId"/>
        /// <see cref="AppointmentItemExtension.GetVCalId(Outlook.AppointmentItem)"/>
        /// <param name="crmId">The CRM id from which the global id should be reverse engineered.</param>
        /// <returns>The reverse-engineered global id.</returns>
        private static string SimulateGlobalId(CrmId crmId)
        {
            byte[] globalId = new byte[89];
            byte[] header   = new byte[40]
            {
                0x04, // 1: EOT
                0x00,
                0x00,
                0x00,
                0x82, // 5: left parenthesis
                0x00,
                0xE0, // 7: shift out
                0x00,
                0x74, // 9: G
                0xC5, // 10: right square bracket
                0xB7, // 11: left brace
                0x10, // 12: start of heading
                0x1A, // 13: ?
                0x82, // 14: left parenthesis
                0xE0, // 15: shift out
                0x08, // 16: ?
                0x00,
                0x00,
                0x00,
                0x00, // 20
                0x00,
                0x00,
                0x00,
                0x00,
                0x00, // 25
                0x00,
                0x00,
                0x00,
                0x00,
                0x00, // 30
                0x00,
                0x00,
                0x00,
                0x00,
                0x00, // 35
                0x00,
                0x31, // 37: s
                0x00,
                0x00,
                0x00  // 40
            };

            byte[] signature  = Encoding.UTF8.GetBytes("vCal-Uid");
            byte[] crmIdBytes = Encoding.UTF8.GetBytes(crmId.ToString());

            Buffer.BlockCopy(header, 0, globalId, 0, 40);
            Buffer.BlockCopy(signature, 0, globalId, 40, signature.Length);
            int cursor = 40 + signature.Length;

            globalId[cursor++] = 0x01;
            globalId[cursor++] = 0;
            globalId[cursor++] = 0;
            Buffer.BlockCopy(crmIdBytes, 0, globalId, cursor, crmIdBytes.Length);

            string result = Encoding.UTF8.GetString(globalId, 0, globalId.Length);

            return(result);
        }
Beispiel #26
0
 protected override void SetMeetingStatus(Outlook.AppointmentItem olItem, EntryValue crmItem)
 {
     olItem.MeetingStatus = CrmId.Get(crmItem.GetValueAsString("assigned_user_id")).Equals(RestAPIWrapper.GetUserId()) ?
                            Outlook.OlMeetingStatus.olMeeting :
                            Outlook.OlMeetingStatus.olMeetingReceived;
 }
Beispiel #27
0
        private void AddMeetingRecipientsFromOutlookToCrm(Outlook.AppointmentItem olItem, CrmId meetingId)
        {
            LogItemAction(olItem, "AppointmentSyncing.AddMeetingRecipientsFromOutlookToCrm");
            foreach (Outlook.Recipient recipient in olItem.Recipients)
            {
                var smtpAddress = recipient.GetSmtpAddress();

                Log.Info($"recepientName= {recipient.Name}, recepient= {smtpAddress}");

                List <AddressResolutionData> resolutions = this.ResolveRecipient(olItem, recipient);

                foreach (AddressResolutionData resolution in resolutions)
                {
                    SetCrmRelationshipFromOutlook(this, meetingId, resolution);
                }
            }
        }
Beispiel #28
0
 /// <summary>
 /// Construct a JSON packet representing this Outlook item, and despatch it to CRM.
 /// </summary>
 /// <param name="olItem">The Outlook item.</param>
 /// <returns>The CRM id of the object created or modified.</returns>
 protected override CrmId ConstructAndDespatchCrmItem(Outlook.ContactItem olItem)
 {
     return(CrmId.Get(RestAPIWrapper.SetEntry(new ProtoContact(olItem).AsNameValues(), this.DefaultCrmModule)));
 }
Beispiel #29
0
 public CallSyncState(AppointmentItem item, CrmId crmId, DateTime modifiedDate) : base(item, crmId, modifiedDate)
 {
 }
 /// <summary>
 /// Set the transmission state of this SyncState object to <see cref="TransmissionState.Synced"/>
 /// and its CRM entry ID to this crmEntryId, and recache its Outlook item.
 /// </summary>
 /// <param name="crmEntryId">The id of the object in CRM.</param>
 internal void SetSynced(CrmId crmEntryId)
 {
     this.SetSynced();
     this.CrmEntryId = crmEntryId;
 }