diff --git a/event/common.go b/event/common.go index a7f19e5..c1fd187 100644 --- a/event/common.go +++ b/event/common.go @@ -329,21 +329,24 @@ const ( // Define Attribute Keys related to history preservation const ( - SaveHistoryDefaultKey = "SaveHistoryDefault" // profile level default - SaveHistoryKey = "SavePeerHistory" - DeleteHistoryDefault = "DefaultDeleteHistory" // used at both profile and contact level. + PreserveHistoryDefaultSettingKey = "SaveHistoryDefault" // profile level default + SaveHistoryKey = "SavePeerHistory" // peer level setting ) // Define Default Attribute Values const ( // Save History has 3 distinct states. By default we refer to the profile level - // attribute SaveHistoryDefaultKey ( default: unset i.e. DefaultDeleteHistory), - // For each contact, if the profile owner confirms this we change to DeleteHistoryConfirmed, + // attribute PreserveHistoryDefaultSettingKey ( default: false i.e. DefaultDeleteHistory), + // For each contact, if the profile owner confirms deletion we change to DeleteHistoryConfirmed, // if the profile owner confirms they want to save history then this becomes SaveHistoryConfirmed // These settings are set at the UI level using Get/SetScopeZoneAttribute with scoped zone: local.profile.* SaveHistoryConfirmed = "SaveHistory" DeleteHistoryConfirmed = "DeleteHistoryConfirmed" SaveHistoryDefault = "DefaultSaveHistory" + + // NOTE: While this says "[DeleteHistory]Default", The actual behaviour will now depend on the + // global app/profile value of PreserveHistoryDefaultSettingKey + DeleteHistoryDefault = "DefaultDeleteHistory" ) // Bool strings diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index c47e223..c484916 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -194,10 +194,16 @@ func (cp *cwtchPeer) UpdateExperiments(enabled bool, experiments map[string]bool cp.experiments = model.InitExperiments(enabled, experiments) } -// NotifySettingsUpdate notifies a Cwtch profile of a change in the nature of global experiments. The Cwtch Profile uses -// this information to update registered extensions. +// NotifySettingsUpdate notifies a Cwtch profile of a change in the nature of global settings. +// The Cwtch Profile uses this information to update registered extensions in addition +// to updating internal settings. func (cp *cwtchPeer) NotifySettingsUpdate(settings settings.GlobalSettings) { log.Debugf("Cwtch Profile Settings Update: %v", settings) + + // update the save history default... + cp.SetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, event.PreserveHistoryDefaultSettingKey, strconv.FormatBool(settings.DefaultSaveHistory)) + + // pass these seetings updates cp.extensionLock.Lock() defer cp.extensionLock.Unlock() for _, extension := range cp.extensions { @@ -545,7 +551,7 @@ func ImportLegacyProfile(profile *model.Profile, cps *CwtchProfileStorage) Cwtch if err == nil { for key, value := range contact.Attributes { switch key { - case event.SaveHistoryKey: + case event.PreserveHistoryDefaultSettingKey: cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.SaveHistoryKey)), value) case string(model.BundleType): cp.AddServer(value) @@ -1537,6 +1543,13 @@ func (cp *cwtchPeer) eventHandler() { } case event.PeerStateChange: handle := ev.Data[event.RemotePeer] + + // we need to do this first because calls in the rest of this block may result in + // events that result the UI or bindings fetching new data. + cp.mutex.Lock() + cp.state[handle] = connections.ConnectionStateToType()[ev.Data[event.ConnectionState]] + cp.mutex.Unlock() + if connections.ConnectionStateToType()[ev.Data[event.ConnectionState]] == connections.AUTHENTICATED { ci, err := cp.FetchConversationInfo(handle) var cid int @@ -1577,9 +1590,6 @@ func (cp *cwtchPeer) eventHandler() { } cp.extensionLock.Unlock() - cp.mutex.Lock() - cp.state[ev.Data[event.RemotePeer]] = connections.ConnectionStateToType()[ev.Data[event.ConnectionState]] - cp.mutex.Unlock() case event.ServerStateChange: cp.mutex.Lock() prevState := cp.state[ev.Data[event.GroupServer]] diff --git a/peer/cwtchprofilestorage.go b/peer/cwtchprofilestorage.go index 784f1fe..c388cd2 100644 --- a/peer/cwtchprofilestorage.go +++ b/peer/cwtchprofilestorage.go @@ -13,6 +13,7 @@ import ( "io" "os" "path/filepath" + "strconv" "strings" "sync" ) @@ -836,23 +837,27 @@ func (cps *CwtchProfileStorage) PurgeConversationChannel(conversation int, chann // PurgeNonSavedMessages deletes all message conversations that are not explicitly set to saved. func (cps *CwtchProfileStorage) PurgeNonSavedMessages() { + // check to see if the profile global setting has been explicitly set to save (peer) conversations by default. defaultSave := false - key, err := cps.LoadProfileKeyValue(TypeAttribute, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.SaveHistoryDefaultKey)).ToString()) + key, err := cps.LoadProfileKeyValue(TypeAttribute, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.PreserveHistoryDefaultSettingKey)).ToString()) if err == nil { - if string(key) == event.SaveHistoryDefault { - defaultSave = true + if defaultSaveSetting, err := strconv.ParseBool(string(key)); err == nil { + defaultSave = defaultSaveSetting } } - // Purge Messages that are not stored... + // For each conversation, all that is not explicitly saved will be lost... ci, err := cps.FetchConversations() if err == nil { for _, conversation := range ci { + // unless this is a server or a group...for which we default save always (for legacy reasons) + // FIXME: revisit this for hybrid groups. if !conversation.IsGroup() && !conversation.IsServer() { - saveHistoryConfirmed := conversation.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.SaveHistoryKey)).ToString()] == event.SaveHistoryConfirmed - deleteHistoryConfirmed := conversation.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.SaveHistoryKey)).ToString()] == event.DeleteHistoryConfirmed + // Note that we only check for confirmed status here...if it is set to any other value we will fallthrough to the default. + saveHistoryConfirmed := conversation.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.PreserveHistoryDefaultSettingKey)).ToString()] == event.SaveHistoryConfirmed + deleteHistoryConfirmed := conversation.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.PreserveHistoryDefaultSettingKey)).ToString()] == event.DeleteHistoryConfirmed // we purge conversation history in two specific instances... - // if the conversation has been explicitly marked as default history confirmed OR + // if the conversation has been explicitly marked as delete history confirmed OR // if save history hasn't been confirmed and default save history is false - i.e. in all other cases if deleteHistoryConfirmed || (!saveHistoryConfirmed && !defaultSave) { log.Debugf("purging conversation...") diff --git a/settings/settings.go b/settings/settings.go index 0093544..e486516 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -57,6 +57,7 @@ type GlobalSettings struct { TorCacheDir string BlodeuweddPath string FontScaling float64 + DefaultSaveHistory bool } var DefaultGlobalSettings = GlobalSettings{ @@ -83,6 +84,7 @@ var DefaultGlobalSettings = GlobalSettings{ TorCacheDir: "", BlodeuweddPath: "", FontScaling: 1.0, // use the system pixel scaling default + DefaultSaveHistory: false, } func InitGlobalSettingsFile(directory string, password string) (*GlobalSettingsFile, error) { @@ -131,6 +133,8 @@ func (globalSettingsFile *GlobalSettingsFile) ReadGlobalSettings() GlobalSetting return settings //firstTime = true } + // note: by giving json.Unmarshal settings we are providing it defacto defaults + // from DefaultGlobalSettings err = json.Unmarshal(settingsBytes, &settings) if err != nil { log.Errorf("Could not parse global ui settings: %v\n", err) diff --git a/storage/v1/profile_store.go b/storage/v1/profile_store.go index 98c6802..db8436b 100644 --- a/storage/v1/profile_store.go +++ b/storage/v1/profile_store.go @@ -65,7 +65,7 @@ func (ps *ProfileStoreV1) load() error { } } - if contact.Attributes[event.SaveHistoryKey] == event.SaveHistoryConfirmed { + if contact.Attributes[event.PreserveHistoryDefaultSettingKey] == event.SaveHistoryConfirmed { ss := NewStreamStore(ps.directory, contact.LocalID, ps.key) cp.Contacts[contact.Onion].Timeline.SetMessages(ss.Read()) }