/// <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. } } }
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); }
/// <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); }
/// <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; } }
/// <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); }
/// <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); }
/// <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); }
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); }
/// <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); }
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; }
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); } } }
/// <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))); }
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; }