1/*
2 * Copyright (c) 2013 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 * IPMonitorControlPrefs.c
26 * - definitions for accessing IPMonitor control preferences
27 */
28
29/*
30 * Modification History
31 *
32 * January 14, 2013	Dieter Siegmund (dieter@apple)
33 * - created
34 */
35
36#include <SystemConfiguration/SCPreferences.h>
37#include <SystemConfiguration/SCPrivate.h>
38#include <SystemConfiguration/scprefs_observer.h>
39#include <TargetConditionals.h>
40#include "IPMonitorControlPrefs.h"
41
42/*
43 * kIPMonitorControlPrefsID
44 * - identifies the IPMonitor preferences file that contains 'Verbose'
45 */
46#define kIPMonitorControlPrefsIDStr	"com.apple.IPMonitor.control.plist"
47#define kIPMonitorControlPrefsID	CFSTR(kIPMonitorControlPrefsIDStr)
48
49/*
50 * kVerbose
51 * - indicates whether IPMonitor is verbose or not
52 */
53#define kVerbose			CFSTR("Verbose")
54
55static SCPreferencesRef			S_prefs;
56static IPMonitorControlPrefsCallBack	S_callback;
57
58static SCPreferencesRef
59IPMonitorControlPrefsGet(void)
60{
61    if (S_prefs == NULL) {
62	IPMonitorControlPrefsInit(NULL, NULL);
63    }
64    return (S_prefs);
65}
66
67static void
68prefs_changed(__unused void * arg)
69{
70    /* get the current value */
71    if (S_callback != NULL) {
72	(*S_callback)(S_prefs);
73    }
74    return;
75}
76
77#if	TARGET_OS_IPHONE
78/*
79 * kIPMonitorControlManangedPrefsID
80 * - identifies the location of the managed preferences file
81 */
82#define kManagedPrefsDirStr		"/Library/Managed Preferences/mobile/"
83#define kIPMonitorControlManagedPrefsID	CFSTR(kManagedPrefsDirStr	\
84					      kIPMonitorControlPrefsIDStr)
85static SCPreferencesRef		S_managed_prefs;
86
87static SCPreferencesRef
88IPMonitorControlManagedPrefsGet(void)
89{
90    if (S_managed_prefs == NULL) {
91	S_managed_prefs
92	    = SCPreferencesCreate(NULL, CFSTR("IPMonitorControlPrefs"),
93				  kIPMonitorControlManagedPrefsID);
94    }
95    return (S_managed_prefs);
96}
97
98static void
99enable_prefs_observer(CFRunLoopRef runloop)
100{
101    CFRunLoopSourceContext 	context;
102    dispatch_block_t		handler;
103    dispatch_queue_t		queue;
104    CFRunLoopSourceRef		source;
105
106    bzero(&context, sizeof(context));
107    context.perform = prefs_changed;
108    source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
109    CFRunLoopAddSource(runloop, source, kCFRunLoopCommonModes);
110    queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
111    handler = ^{
112	if (source != NULL) {
113	    CFRunLoopSourceSignal(source);
114	    if (runloop != NULL) {
115		CFRunLoopWakeUp(runloop);
116	    }
117	};
118    };
119    _scprefs_observer_watch(scprefs_observer_type_global,
120			    kIPMonitorControlPrefsIDStr,
121			    queue, handler);
122    return;
123}
124
125#else	/* TARGET_OS_IPHONE */
126
127static void
128enable_prefs_observer(CFRunLoopRef runloop)
129{
130    return;
131}
132
133#endif	/* TARGET_OS_IPHONE */
134
135static void
136IPMonitorControlPrefsChanged(SCPreferencesRef prefs,
137			     SCPreferencesNotification type,
138			     void * info)
139{
140    prefs_changed(NULL);
141    return;
142}
143
144__private_extern__ SCPreferencesRef
145IPMonitorControlPrefsInit(CFRunLoopRef runloop,
146			  IPMonitorControlPrefsCallBack callback)
147{
148    S_prefs = SCPreferencesCreate(NULL, CFSTR("IPMonitorControlPrefs"),
149				  kIPMonitorControlPrefsID);
150    if (runloop != NULL && callback != NULL) {
151	S_callback = callback;
152	SCPreferencesSetCallback(S_prefs, IPMonitorControlPrefsChanged, NULL);
153	SCPreferencesScheduleWithRunLoop(S_prefs, runloop,
154					 kCFRunLoopCommonModes);
155	enable_prefs_observer(runloop);
156    }
157    return (S_prefs);
158}
159
160static Boolean
161IPMonitorControlPrefsSave(void)
162{
163    Boolean		saved = FALSE;
164
165    if (S_prefs != NULL) {
166	saved = SCPreferencesCommitChanges(S_prefs);
167	SCPreferencesSynchronize(S_prefs);
168    }
169    return (saved);
170}
171
172static CFBooleanRef
173prefs_get_boolean(CFStringRef key)
174{
175    CFBooleanRef	b = NULL;
176
177#if	TARGET_OS_IPHONE
178    b = SCPreferencesGetValue(IPMonitorControlManagedPrefsGet(), key);
179    b = isA_CFBoolean(b);
180#endif	/* TARGET_OS_IPHONE */
181    if (b == NULL) {
182	b = SCPreferencesGetValue(IPMonitorControlPrefsGet(), key);
183	b = isA_CFBoolean(b);
184    }
185    return (b);
186}
187
188static void
189prefs_set_boolean(CFStringRef key, CFBooleanRef b)
190{
191    SCPreferencesRef	prefs = IPMonitorControlPrefsGet();
192
193    if (prefs != NULL) {
194	if (isA_CFBoolean(b) == NULL) {
195	    SCPreferencesRemoveValue(prefs, key);
196	}
197	else {
198	    SCPreferencesSetValue(prefs, key, b);
199	}
200    }
201    return;
202}
203
204static void
205IPMonitorControlPrefsRefresh(void)
206{
207    if (S_prefs != NULL) {
208	SCPreferencesSynchronize(S_prefs);
209    }
210#if	TARGET_OS_IPHONE
211    if (S_managed_prefs != NULL) {
212	SCPreferencesSynchronize(S_managed_prefs);
213    }
214#endif	/* TARGET_OS_IPHONE */
215    return;
216}
217
218/**
219 ** Get
220 **/
221__private_extern__ Boolean
222IPMonitorControlPrefsIsVerbose(void)
223{
224    CFBooleanRef	b;
225    Boolean		verbose = FALSE;
226
227    b = prefs_get_boolean(kVerbose);
228    if (b != NULL) {
229	verbose = CFBooleanGetValue(b);
230    }
231    /* flush the backing store */
232    IPMonitorControlPrefsRefresh();
233    return (verbose);
234}
235
236/**
237 ** Set
238 **/
239__private_extern__ Boolean
240IPMonitorControlPrefsSetVerbose(Boolean verbose)
241{
242    if (verbose == FALSE) {
243	prefs_set_boolean(kVerbose, NULL);
244    }
245    else {
246	prefs_set_boolean(kVerbose, kCFBooleanTrue);
247    }
248    return (IPMonitorControlPrefsSave());
249}
250
251#ifdef TEST_IPMONITORCONTROLPREFS
252int
253main(int argc, char * argv[])
254{
255    Boolean	need_usage = FALSE;
256    Boolean	success = FALSE;
257
258    if (argc < 2) {
259	need_usage = TRUE;
260    }
261    else if (strcasecmp(argv[1], "on") == 0) {
262	success = IPMonitorControlPrefsSetVerbose(TRUE);
263    }
264    else if (strcasecmp(argv[1], "off") == 0) {
265	success = IPMonitorControlPrefsSetVerbose(FALSE);
266    }
267    else {
268	need_usage = TRUE;
269    }
270    if (need_usage) {
271	fprintf(stderr, "usage: %s ( on | off )\n", argv[0]);
272	exit(1);
273    }
274    if (success == FALSE) {
275	fprintf(stderr, "failed to save prefs\n");
276	exit(2);
277    }
278    exit(0);
279    return (0);
280}
281
282#endif /* TEST_IPMONITORCONTROLPREFS */
283