/ OSX / Keychain Circle Notification / KNPersistentState.m
KNPersistentState.m
 1  /*
 2   * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
 3   *
 4   * @APPLE_LICENSE_HEADER_START@
 5   * 
 6   * This file contains Original Code and/or Modifications of Original Code
 7   * as defined in and that are subject to the Apple Public Source License
 8   * Version 2.0 (the 'License'). You may not use this file except in
 9   * compliance with the License. Please obtain a copy of the License at
10   * http://www.opensource.apple.com/apsl/ and read it before using this
11   * file.
12   * 
13   * The Original Code and all software distributed under the License are
14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18   * Please see the License for the specific language governing rights and
19   * limitations under the License.
20   * 
21   * @APPLE_LICENSE_HEADER_END@
22   */
23  
24  
25  #import "KNPersistentState.h"
26  #import <utilities/debugging.h>
27  
28  @implementation KNPersistentState
29  
30  -(NSURL*)urlForStorage
31  {
32  	return [NSURL URLWithString:@"Preferences/com.apple.security.KCN.plist" relativeToURL:[[NSFileManager defaultManager] URLForDirectory:NSLibraryDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]];
33  }
34  
35  +(instancetype)loadFromStorage
36  {
37  	KNPersistentState *state = [KNPersistentState new];
38      if (!state) {
39          return state;
40      }
41      
42      id plist = @{@"lastWritten": [NSDate distantPast]};
43  
44      NSError *error = nil;
45      NSData *stateData = [NSData dataWithContentsOfURL:[state urlForStorage] options:0 error:&error];
46      if (!stateData) {
47          secdebug("kcn", "Can't read state data (p=%@, err=%@)", [state urlForStorage], error);
48      } else {
49          NSPropertyListFormat format;
50          plist = [NSPropertyListSerialization propertyListWithData:stateData options: NSPropertyListMutableContainersAndLeaves format:&format error:&error];
51          
52          if (plist == nil) {
53              secdebug("kcn", "Can't deserialize %@, e=%@", stateData, error);
54          }
55      }
56      
57      state.lastCircleStatus 						= plist[@"lastCircleStatus"] ? [plist[@"lastCircleStatus"] intValue] : kSOSCCCircleAbsent;
58      state.lastWritten							= plist[@"lastWritten"];
59  	state.pendingApplicationReminder			= plist[@"pendingApplicationReminder"] ?: [NSDate distantFuture];
60  	state.applicationDate						= plist[@"applicationDate"]            ?: [NSDate distantPast];
61  	state.debugLeftReason						= plist[@"debugLeftReason"];
62  	state.pendingApplicationReminderInterval	= plist[@"pendingApplicationReminderInterval"];
63  	state.absentCircleWithNoReason				= plist[@"absentCircleWithNoReason"] ? [plist[@"absentCircleWithNoReason"] intValue] : NO;
64  
65      if (!state.pendingApplicationReminderInterval || [state.pendingApplicationReminderInterval doubleValue] <= 0) {
66          state.pendingApplicationReminderInterval = [NSNumber numberWithUnsignedInt: 24*60*60];
67      }
68      
69      return state;
70  }
71  
72  -(void)writeToStorage
73  {
74      NSMutableDictionary *plist = [@{@"lastCircleStatus"					 : [NSNumber numberWithInt:self.lastCircleStatus],
75  									@"lastWritten"						 : [NSDate date],
76  									@"applicationDate"					 : self.applicationDate,
77  									@"pendingApplicationReminder"		 : self.pendingApplicationReminder,
78  									@"pendingApplicationReminderInterval": self.pendingApplicationReminderInterval,
79  									@"absentCircleWithNoReason" 		 : [NSNumber numberWithBool:self.absentCircleWithNoReason],
80  								   } mutableCopy];
81  	if (self.debugLeftReason)
82  		plist[@"debugLeftReason"] = self.debugLeftReason;
83      secdebug("kcn", "writeToStorage plist=%@", plist);
84  	
85      NSError *error = nil;
86      NSData *stateData = [NSPropertyListSerialization dataWithPropertyList:plist format:NSPropertyListXMLFormat_v1_0 options:kCFPropertyListImmutable error:&error];
87      if (!stateData) {
88          secdebug("kcn", "Can't serialize %@: %@", plist, error);
89          return;
90      }
91      if (![stateData writeToURL:[self urlForStorage] options:NSDataWritingAtomic error:&error]) {
92          secdebug("kcn", "Can't write to %@, error=%@", [self urlForStorage], error);
93      }
94  }
95  
96  
97  @end