~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/modules/libpref/src/nsPrefBranch.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is Mozilla Communicator client code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is 
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 * Alec Flett <alecf@netscape.com>
 
24
 * Brian Nesse <bnesse@netscape.com>
 
25
 *
 
26
 * Alternatively, the contents of this file may be used under the terms of
 
27
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 
28
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
29
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
30
 * of those above. If you wish to allow use of your version of this file only
 
31
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
32
 * use your version of this file under the terms of the NPL, indicate your
 
33
 * decision by deleting the provisions above and replace them with the notice
 
34
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
35
 * the provisions above, a recipient may use your version of this file under
 
36
 * the terms of any one of the NPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
#include "nsPrefBranch.h"
 
41
#include "nsILocalFile.h"
 
42
#include "nsIObserverService.h"
 
43
#include "nsXPCOM.h"
 
44
#include "nsISupportsPrimitives.h"
 
45
#include "nsIDirectoryService.h"
 
46
#include "nsString.h"
 
47
#include "nsReadableUtils.h"
 
48
#include "nsXPIDLString.h"
 
49
#include "nsIScriptSecurityManager.h"
 
50
#include "nsIStringBundle.h"
 
51
#include "prefapi.h"
 
52
#include "prmem.h"
 
53
#include "pldhash.h"
 
54
 
 
55
#include "nsIFileSpec.h"  // this should be removed eventually
 
56
#include "prefapi_private_data.h"
 
57
 
 
58
// Definitions
 
59
struct EnumerateData {
 
60
  const char  *parent;
 
61
  nsVoidArray *pref_list;
 
62
};
 
63
 
 
64
struct PrefCallbackData {
 
65
  nsIPrefBranch *pBranch;
 
66
  nsISupports   *pObserver;
 
67
  PRBool        bIsWeakRef;
 
68
};
 
69
 
 
70
 
 
71
// Prototypes
 
72
PR_STATIC_CALLBACK(PLDHashOperator)
 
73
  pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh,
 
74
                 PRUint32 i, void *arg);
 
75
PR_STATIC_CALLBACK(nsresult)
 
76
  NotifyObserver(const char *newpref, void *data);
 
77
 
 
78
/*
 
79
 * Constructor/Destructor
 
80
 */
 
81
 
 
82
nsPrefBranch::nsPrefBranch(const char *aPrefRoot, PRBool aDefaultBranch)
 
83
  : mObservers(nsnull)
 
84
{
 
85
  mPrefRoot = aPrefRoot;
 
86
  mPrefRootLength = mPrefRoot.Length();
 
87
  mIsDefault = aDefaultBranch;
 
88
 
 
89
  nsCOMPtr<nsIObserverService> observerService = 
 
90
           do_GetService("@mozilla.org/observer-service;1");
 
91
  if (observerService) {
 
92
    ++mRefCnt;    // Our refcnt must be > 0 when we call this, or we'll get deleted!
 
93
    // add weak so we don't have to clean up at shutdown
 
94
    observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
 
95
    --mRefCnt;
 
96
  }
 
97
}
 
98
 
 
99
nsPrefBranch::~nsPrefBranch()
 
100
{
 
101
  freeObserverList();
 
102
}
 
103
 
 
104
 
 
105
/*
 
106
 * nsISupports Implementation
 
107
 */
 
108
 
 
109
NS_IMPL_THREADSAFE_ADDREF(nsPrefBranch)
 
110
NS_IMPL_THREADSAFE_RELEASE(nsPrefBranch)
 
111
 
 
112
NS_INTERFACE_MAP_BEGIN(nsPrefBranch)
 
113
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefBranch)
 
114
  NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
 
115
  NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
 
116
  NS_INTERFACE_MAP_ENTRY(nsISecurityPref)
 
117
  NS_INTERFACE_MAP_ENTRY(nsIObserver)
 
118
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 
119
NS_INTERFACE_MAP_END
 
120
 
 
121
 
 
122
/*
 
123
 * nsIPrefBranch Implementation
 
124
 */
 
125
 
 
126
NS_IMETHODIMP nsPrefBranch::GetRoot(char * *aRoot)
 
127
{
 
128
  NS_ENSURE_ARG_POINTER(aRoot);
 
129
 
 
130
  mPrefRoot.Truncate(mPrefRootLength);
 
131
  *aRoot = ToNewCString(mPrefRoot);
 
132
  return NS_OK;
 
133
}
 
134
 
 
135
NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, PRInt32 *_retval)
 
136
{
 
137
  const char *pref;
 
138
  nsresult   rv;
 
139
 
 
140
  rv = getValidatedPrefName(aPrefName, &pref);
 
141
  if (NS_FAILED(rv))
 
142
    return rv;
 
143
 
 
144
  *_retval = PREF_GetPrefType(pref);
 
145
  return NS_OK;
 
146
}
 
147
 
 
148
NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, PRBool *_retval)
 
149
{
 
150
  const char *pref;
 
151
  nsresult   rv;
 
152
 
 
153
  rv = getValidatedPrefName(aPrefName, &pref);
 
154
  if (NS_SUCCEEDED(rv)) {
 
155
    rv = PREF_GetBoolPref(pref, _retval, mIsDefault);
 
156
  }
 
157
  return rv;
 
158
}
 
159
 
 
160
NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, PRInt32 aValue)
 
161
{
 
162
  const char *pref;
 
163
  nsresult   rv;
 
164
 
 
165
  rv = getValidatedPrefName(aPrefName, &pref);
 
166
  if (NS_SUCCEEDED(rv)) {
 
167
    rv = PREF_SetBoolPref(pref, aValue, mIsDefault);
 
168
  }
 
169
  return rv;
 
170
}
 
171
 
 
172
NS_IMETHODIMP nsPrefBranch::GetCharPref(const char *aPrefName, char **_retval)
 
173
{
 
174
  const char *pref;
 
175
  nsresult   rv;
 
176
 
 
177
  rv = getValidatedPrefName(aPrefName, &pref);
 
178
  if (NS_SUCCEEDED(rv)) {
 
179
    rv = PREF_CopyCharPref(pref, _retval, mIsDefault);
 
180
  }
 
181
  return rv;
 
182
}
 
183
 
 
184
NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPrefName, const char *aValue)
 
185
{
 
186
  const char *pref;
 
187
  nsresult   rv;
 
188
 
 
189
  NS_ENSURE_ARG_POINTER(aValue);
 
190
  rv = getValidatedPrefName(aPrefName, &pref);
 
191
  if (NS_SUCCEEDED(rv)) {
 
192
    rv = PREF_SetCharPref(pref, aValue, mIsDefault);
 
193
  }
 
194
  return rv;
 
195
}
 
196
 
 
197
NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPrefName, PRInt32 *_retval)
 
198
{
 
199
  const char *pref;
 
200
  nsresult   rv;
 
201
 
 
202
  rv = getValidatedPrefName(aPrefName, &pref);
 
203
  if (NS_SUCCEEDED(rv)) {
 
204
    rv = PREF_GetIntPref(pref, _retval, mIsDefault);
 
205
  }
 
206
  return rv;
 
207
}
 
208
 
 
209
NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPrefName, PRInt32 aValue)
 
210
{
 
211
  const char *pref;
 
212
  nsresult   rv;
 
213
 
 
214
  rv = getValidatedPrefName(aPrefName, &pref);
 
215
  if (NS_SUCCEEDED(rv)) {
 
216
    rv = PREF_SetIntPref(pref, aValue, mIsDefault);
 
217
  }
 
218
  return rv;
 
219
}
 
220
 
 
221
NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & aType, void * *_retval)
 
222
{
 
223
  nsresult       rv;
 
224
  nsXPIDLCString utf8String;
 
225
 
 
226
  // we have to do this one first because it's different than all the rest
 
227
  if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
 
228
    nsCOMPtr<nsIPrefLocalizedString> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
 
229
 
 
230
    if (NS_SUCCEEDED(rv)) {
 
231
      const char *pref;
 
232
      PRBool  bNeedDefault = PR_FALSE;
 
233
 
 
234
      rv = getValidatedPrefName(aPrefName, &pref);
 
235
      if (NS_FAILED(rv))
 
236
        return rv;
 
237
 
 
238
      if (mIsDefault) {
 
239
        bNeedDefault = PR_TRUE;
 
240
      } else {
 
241
        // if there is no user (or locked) value
 
242
        if (!PREF_HasUserPref(pref) && !PREF_PrefIsLocked(pref)) {
 
243
          bNeedDefault = PR_TRUE;
 
244
        }
 
245
      }
 
246
 
 
247
      // if we need to fetch the default value, do that instead, otherwise use the
 
248
      // value we pulled in at the top of this function
 
249
      if (bNeedDefault) {
 
250
        nsXPIDLString utf16String;
 
251
        rv = GetDefaultFromPropertiesFile(pref, getter_Copies(utf16String));
 
252
        if (NS_SUCCEEDED(rv)) {
 
253
          rv = theString->SetData(utf16String.get());
 
254
        }
 
255
      } else {
 
256
        rv = GetCharPref(aPrefName, getter_Copies(utf8String));
 
257
        if (NS_SUCCEEDED(rv)) {
 
258
          rv = theString->SetData(NS_ConvertUTF8toUCS2(utf8String).get());
 
259
        }
 
260
      }
 
261
      if (NS_SUCCEEDED(rv)) {
 
262
        nsIPrefLocalizedString *temp = theString;
 
263
 
 
264
        NS_ADDREF(temp);
 
265
        *_retval = (void *)temp;
 
266
      }
 
267
    }
 
268
 
 
269
    return rv;
 
270
  }
 
271
 
 
272
  // if we can't get the pref, there's no point in being here
 
273
  rv = GetCharPref(aPrefName, getter_Copies(utf8String));
 
274
  if (NS_FAILED(rv)) {
 
275
    return rv;
 
276
  }
 
277
 
 
278
  if (aType.Equals(NS_GET_IID(nsILocalFile))) {
 
279
    nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
 
280
 
 
281
    if (NS_SUCCEEDED(rv)) {
 
282
      rv = file->SetPersistentDescriptor(utf8String);
 
283
      if (NS_SUCCEEDED(rv)) {
 
284
        nsILocalFile *temp = file;
 
285
 
 
286
        NS_ADDREF(temp);
 
287
        *_retval = (void *)temp;
 
288
        return NS_OK;
 
289
      }
 
290
    }
 
291
    return rv;
 
292
  }
 
293
 
 
294
  if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
 
295
    nsACString::const_iterator keyBegin, strEnd;
 
296
    utf8String.BeginReading(keyBegin);
 
297
    utf8String.EndReading(strEnd);    
 
298
 
 
299
    // The pref has the format: [fromKey]a/b/c
 
300
    if (*keyBegin++ != '[')        
 
301
        return NS_ERROR_FAILURE;
 
302
    nsACString::const_iterator keyEnd(keyBegin);
 
303
    if (!FindCharInReadable(']', keyEnd, strEnd))
 
304
        return NS_ERROR_FAILURE;
 
305
    nsCAutoString key(Substring(keyBegin, keyEnd));
 
306
    
 
307
    nsCOMPtr<nsILocalFile> fromFile;        
 
308
    nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
 
309
    if (NS_FAILED(rv))
 
310
      return rv;
 
311
    rv = directoryService->Get(key.get(), NS_GET_IID(nsILocalFile), getter_AddRefs(fromFile));
 
312
    if (NS_FAILED(rv))
 
313
      return rv;
 
314
    
 
315
    nsCOMPtr<nsILocalFile> theFile;
 
316
    rv = NS_NewNativeLocalFile(nsCString(), PR_TRUE, getter_AddRefs(theFile));
 
317
    if (NS_FAILED(rv))
 
318
      return rv;
 
319
    rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd));
 
320
    if (NS_FAILED(rv))
 
321
      return rv;
 
322
    nsCOMPtr<nsIRelativeFilePref> relativePref;
 
323
    rv = NS_NewRelativeFilePref(theFile, key, getter_AddRefs(relativePref));
 
324
    if (NS_FAILED(rv))
 
325
      return rv;
 
326
 
 
327
    *_retval = relativePref;
 
328
    NS_ADDREF(NS_STATIC_CAST(nsIRelativeFilePref*, *_retval));
 
329
    return NS_OK;
 
330
  }
 
331
 
 
332
  if (aType.Equals(NS_GET_IID(nsISupportsString))) {
 
333
    nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
 
334
 
 
335
    if (NS_SUCCEEDED(rv)) {
 
336
      rv = theString->SetData(NS_ConvertUTF8toUCS2(utf8String));
 
337
      if (NS_SUCCEEDED(rv)) {
 
338
        nsISupportsString *temp = theString;
 
339
 
 
340
        NS_ADDREF(temp);
 
341
        *_retval = (void *)temp;
 
342
        return NS_OK;
 
343
      }
 
344
    }
 
345
    return rv;
 
346
  }
 
347
 
 
348
  // This is deprecated and you should not be using it
 
349
  if (aType.Equals(NS_GET_IID(nsIFileSpec))) {
 
350
    nsCOMPtr<nsIFileSpec> file(do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv));
 
351
 
 
352
    if (NS_SUCCEEDED(rv)) {
 
353
      nsIFileSpec *temp = file;
 
354
      PRBool      valid;
 
355
 
 
356
      file->SetPersistentDescriptorString(utf8String);  // only returns NS_OK
 
357
      file->IsValid(&valid);
 
358
      if (!valid) {
 
359
        /* if the string wasn't a valid persistent descriptor, it might be a valid native path */
 
360
        file->SetNativePath(utf8String);
 
361
      }
 
362
      NS_ADDREF(temp);
 
363
      *_retval = (void *)temp;
 
364
      return NS_OK;
 
365
    }
 
366
    return rv;
 
367
  }
 
368
 
 
369
  NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
 
370
  return NS_NOINTERFACE;
 
371
}
 
372
 
 
373
NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
 
374
{
 
375
  nsresult   rv = NS_NOINTERFACE;
 
376
 
 
377
  if (aType.Equals(NS_GET_IID(nsILocalFile))) {
 
378
    nsCOMPtr<nsILocalFile> file = do_QueryInterface(aValue);
 
379
    nsCAutoString descriptorString;
 
380
 
 
381
    rv = file->GetPersistentDescriptor(descriptorString);
 
382
    if (NS_SUCCEEDED(rv)) {
 
383
      rv = SetCharPref(aPrefName, descriptorString.get());
 
384
    }
 
385
    return rv;
 
386
  }
 
387
 
 
388
  if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
 
389
    nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
 
390
    if (!relFilePref)
 
391
      return NS_NOINTERFACE;
 
392
    
 
393
    nsCOMPtr<nsILocalFile> file;
 
394
    relFilePref->GetFile(getter_AddRefs(file));
 
395
    if (!file)
 
396
      return NS_ERROR_FAILURE;
 
397
    nsCAutoString relativeToKey;
 
398
    (void) relFilePref->GetRelativeToKey(relativeToKey);
 
399
 
 
400
    nsCOMPtr<nsILocalFile> relativeToFile;        
 
401
    nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
 
402
    if (NS_FAILED(rv))
 
403
      return rv;
 
404
    rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsILocalFile), getter_AddRefs(relativeToFile));
 
405
    if (NS_FAILED(rv))
 
406
      return rv;
 
407
 
 
408
    nsCAutoString relDescriptor;
 
409
    rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
 
410
    if (NS_FAILED(rv))
 
411
      return rv;
 
412
    
 
413
    nsCAutoString descriptorString;
 
414
    descriptorString.Append('[');
 
415
    descriptorString.Append(relativeToKey);
 
416
    descriptorString.Append(']');
 
417
    descriptorString.Append(relDescriptor);
 
418
    return SetCharPref(aPrefName, descriptorString.get());
 
419
  }
 
420
 
 
421
  if (aType.Equals(NS_GET_IID(nsISupportsString))) {
 
422
    nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
 
423
 
 
424
    if (theString) {
 
425
      nsAutoString wideString;
 
426
 
 
427
      rv = theString->GetData(wideString);
 
428
      if (NS_SUCCEEDED(rv)) {
 
429
        rv = SetCharPref(aPrefName, NS_ConvertUCS2toUTF8(wideString).get());
 
430
      }
 
431
    }
 
432
    return rv;
 
433
  }
 
434
 
 
435
  if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
 
436
    nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue);
 
437
 
 
438
    if (theString) {
 
439
      nsXPIDLString wideString;
 
440
 
 
441
      rv = theString->GetData(getter_Copies(wideString));
 
442
      if (NS_SUCCEEDED(rv)) {
 
443
        rv = SetCharPref(aPrefName, NS_ConvertUCS2toUTF8(wideString).get());
 
444
      }
 
445
    }
 
446
    return rv;
 
447
  }
 
448
 
 
449
  // This is deprecated and you should not be using it
 
450
  if (aType.Equals(NS_GET_IID(nsIFileSpec))) {
 
451
    nsCOMPtr<nsIFileSpec> file = do_QueryInterface(aValue);
 
452
    nsXPIDLCString descriptorString;
 
453
 
 
454
    rv = file->GetPersistentDescriptorString(getter_Copies(descriptorString));
 
455
    if (NS_SUCCEEDED(rv)) {
 
456
      rv = SetCharPref(aPrefName, descriptorString);
 
457
    }
 
458
    return rv;
 
459
  }
 
460
 
 
461
  NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type");
 
462
  return NS_NOINTERFACE;
 
463
}
 
464
 
 
465
NS_IMETHODIMP nsPrefBranch::ClearUserPref(const char *aPrefName)
 
466
{
 
467
  const char *pref;
 
468
  nsresult   rv;
 
469
 
 
470
  rv = getValidatedPrefName(aPrefName, &pref);
 
471
  if (NS_SUCCEEDED(rv)) {
 
472
    rv = PREF_ClearUserPref(pref);
 
473
  }
 
474
  return rv;
 
475
}
 
476
 
 
477
NS_IMETHODIMP nsPrefBranch::PrefHasUserValue(const char *aPrefName, PRBool *_retval)
 
478
{
 
479
  const char *pref;
 
480
  nsresult   rv;
 
481
 
 
482
  NS_ENSURE_ARG_POINTER(_retval);
 
483
 
 
484
  rv = getValidatedPrefName(aPrefName, &pref);
 
485
  if (NS_SUCCEEDED(rv)) {
 
486
    *_retval = PREF_HasUserPref(pref);
 
487
  }
 
488
  return rv;
 
489
}
 
490
 
 
491
NS_IMETHODIMP nsPrefBranch::LockPref(const char *aPrefName)
 
492
{
 
493
  const char *pref;
 
494
  nsresult   rv;
 
495
 
 
496
  rv = getValidatedPrefName(aPrefName, &pref);
 
497
  if (NS_SUCCEEDED(rv)) {
 
498
    rv = PREF_LockPref(pref, PR_TRUE);
 
499
  }
 
500
  return rv;
 
501
}
 
502
 
 
503
NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *aPrefName, PRBool *_retval)
 
504
{
 
505
  const char *pref;
 
506
  nsresult   rv;
 
507
 
 
508
  NS_ENSURE_ARG_POINTER(_retval);
 
509
 
 
510
  rv = getValidatedPrefName(aPrefName, &pref);
 
511
  if (NS_SUCCEEDED(rv)) {
 
512
    *_retval = PREF_PrefIsLocked(pref);
 
513
  }
 
514
  return rv;
 
515
}
 
516
 
 
517
NS_IMETHODIMP nsPrefBranch::UnlockPref(const char *aPrefName)
 
518
{
 
519
  const char *pref;
 
520
  nsresult   rv;
 
521
 
 
522
  rv = getValidatedPrefName(aPrefName, &pref);
 
523
  if (NS_SUCCEEDED(rv)) {
 
524
    rv = PREF_LockPref(pref, PR_FALSE);
 
525
  }
 
526
  return rv;
 
527
}
 
528
 
 
529
/* void resetBranch (in string startingAt); */
 
530
NS_IMETHODIMP nsPrefBranch::ResetBranch(const char *aStartingAt)
 
531
{
 
532
  return NS_ERROR_NOT_IMPLEMENTED;
 
533
}
 
534
 
 
535
NS_IMETHODIMP nsPrefBranch::DeleteBranch(const char *aStartingAt)
 
536
{
 
537
  const char *pref;
 
538
  nsresult   rv;
 
539
 
 
540
  rv = getValidatedPrefName(aStartingAt, &pref);
 
541
  if (NS_SUCCEEDED(rv)) {
 
542
    rv = PREF_DeleteBranch(pref);
 
543
  }
 
544
  return rv;
 
545
}
 
546
 
 
547
NS_IMETHODIMP nsPrefBranch::GetChildList(const char *aStartingAt, PRUint32 *aCount, char ***aChildArray)
 
548
{
 
549
  char**          outArray;
 
550
  char*           theElement;
 
551
  PRInt32         numPrefs;
 
552
  PRInt32         dwIndex;
 
553
  EnumerateData   ed;
 
554
  nsAutoVoidArray prefArray;
 
555
 
 
556
  NS_ENSURE_ARG_POINTER(aStartingAt);
 
557
  NS_ENSURE_ARG_POINTER(aCount);
 
558
  NS_ENSURE_ARG_POINTER(aChildArray);
 
559
 
 
560
  if (!gHashTable.ops) {
 
561
    *aChildArray = nsnull;
 
562
    *aCount = 0;
 
563
    return NS_ERROR_NOT_INITIALIZED;
 
564
  }
 
565
 
 
566
  // this will contain a list of all the pref name strings
 
567
  // allocate on the stack for speed
 
568
 
 
569
  ed.parent = getPrefName(aStartingAt);
 
570
  ed.pref_list = &prefArray;
 
571
  PL_DHashTableEnumerate(&gHashTable, pref_enumChild, &ed);
 
572
 
 
573
  // now that we've built up the list, run the callback on
 
574
  // all the matching elements
 
575
  numPrefs = prefArray.Count();
 
576
 
 
577
  if (numPrefs) {
 
578
    outArray = (char **)nsMemory::Alloc(numPrefs * sizeof(char *));
 
579
    if (!outArray)
 
580
      return NS_ERROR_OUT_OF_MEMORY;
 
581
 
 
582
    for (dwIndex = 0; dwIndex < numPrefs; ++dwIndex) {
 
583
      // we need to lop off mPrefRoot in case the user is planning to pass this
 
584
      // back to us because if they do we are going to add mPrefRoot again.
 
585
      theElement = ((char *)prefArray.ElementAt(dwIndex)) + mPrefRootLength;
 
586
      outArray[dwIndex] = (char *)nsMemory::Clone(theElement, strlen(theElement) + 1);
 
587
 
 
588
      if (!outArray[dwIndex]) {
 
589
        // we ran out of memory... this is annoying
 
590
        NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex, outArray);
 
591
        return NS_ERROR_OUT_OF_MEMORY;
 
592
      }
 
593
    }
 
594
    *aChildArray = outArray;
 
595
  } else {
 
596
    *aChildArray = nsnull;
 
597
  } /* endif */
 
598
  *aCount = numPrefs;
 
599
 
 
600
  return NS_OK;
 
601
}
 
602
 
 
603
 
 
604
/*
 
605
 *  nsIPrefBranchInternal methods
 
606
 */
 
607
 
 
608
NS_IMETHODIMP nsPrefBranch::AddObserver(const char *aDomain, nsIObserver *aObserver, PRBool aHoldWeak)
 
609
{
 
610
  PrefCallbackData *pCallback;
 
611
  const char *pref;
 
612
 
 
613
  NS_ENSURE_ARG_POINTER(aDomain);
 
614
  NS_ENSURE_ARG_POINTER(aObserver);
 
615
 
 
616
  if (!mObservers) {
 
617
    mObservers = new nsAutoVoidArray();
 
618
    if (nsnull == mObservers)
 
619
      return NS_ERROR_OUT_OF_MEMORY;
 
620
  }
 
621
 
 
622
  pCallback = (PrefCallbackData *)nsMemory::Alloc(sizeof(PrefCallbackData));
 
623
  if (nsnull == pCallback)
 
624
    return NS_ERROR_OUT_OF_MEMORY;
 
625
 
 
626
  pCallback->pBranch = NS_STATIC_CAST(nsIPrefBranch *, this);
 
627
  pCallback->bIsWeakRef = aHoldWeak;
 
628
 
 
629
  // hold a weak reference to the observer if so requested
 
630
  nsCOMPtr<nsISupports> observerRef;
 
631
  if (aHoldWeak) {
 
632
    nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
 
633
    if (!weakRefFactory) {
 
634
      // the caller didn't give us a object that supports weak reference... tell them
 
635
      nsMemory::Free(pCallback);
 
636
      return NS_ERROR_INVALID_ARG;
 
637
    }
 
638
    observerRef = do_GetWeakReference(weakRefFactory);
 
639
  } else {
 
640
    observerRef = aObserver;
 
641
  }
 
642
  pCallback->pObserver = observerRef;
 
643
  NS_ADDREF(pCallback->pObserver);
 
644
 
 
645
  mObservers->AppendElement(pCallback);
 
646
  mObserverDomains.AppendCString(nsCString(aDomain));
 
647
 
 
648
  // We must pass a fully qualified preference name to the callback
 
649
  pref = getPrefName(aDomain); // aDomain == nsnull only possible failure, trapped above
 
650
  PREF_RegisterCallback(pref, NotifyObserver, pCallback);
 
651
  return NS_OK;
 
652
}
 
653
 
 
654
NS_IMETHODIMP nsPrefBranch::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
 
655
{
 
656
  const char *pref;
 
657
  PrefCallbackData *pCallback;
 
658
  PRInt32 count;
 
659
  PRInt32 i;
 
660
  nsresult rv;
 
661
  nsCAutoString domain;
 
662
 
 
663
  NS_ENSURE_ARG_POINTER(aDomain);
 
664
  NS_ENSURE_ARG_POINTER(aObserver);
 
665
 
 
666
  if (!mObservers)
 
667
    return NS_OK;
 
668
    
 
669
  // need to find the index of observer, so we can remove it from the domain list too
 
670
  count = mObservers->Count();
 
671
  if (count == 0)
 
672
    return NS_OK;
 
673
 
 
674
  for (i = 0; i < count; i++) {
 
675
    pCallback = (PrefCallbackData *)mObservers->ElementAt(i);
 
676
    if (pCallback) {
 
677
     nsCOMPtr<nsISupports> observerRef;
 
678
     if (pCallback->bIsWeakRef) {
 
679
       nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
 
680
       if (weakRefFactory)
 
681
         observerRef = do_GetWeakReference(aObserver);
 
682
     }
 
683
     if (!observerRef)
 
684
       observerRef = aObserver;
 
685
 
 
686
      if (pCallback->pObserver == observerRef) {
 
687
        mObserverDomains.CStringAt(i, domain);
 
688
        if (domain.Equals(aDomain)) {
 
689
          // We must pass a fully qualified preference name to remove the callback
 
690
          pref = getPrefName(aDomain); // aDomain == nsnull only possible failure, trapped above
 
691
          rv = PREF_UnregisterCallback(pref, NotifyObserver, pCallback);
 
692
          if (NS_SUCCEEDED(rv)) {
 
693
            // Remove this observer from our array so that nobody else can remove
 
694
            // what we're trying to remove ourselves right now.
 
695
            mObservers->RemoveElementAt(i);
 
696
            mObserverDomains.RemoveCStringAt(i);
 
697
            NS_RELEASE(pCallback->pObserver);
 
698
            nsMemory::Free(pCallback);
 
699
          }
 
700
          return rv;
 
701
        }
 
702
      }
 
703
    }
 
704
  }
 
705
 
 
706
  return NS_OK;
 
707
}
 
708
 
 
709
NS_IMETHODIMP nsPrefBranch::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
 
710
{
 
711
  // watch for xpcom shutdown and free our observers to eliminate any cyclic references
 
712
  if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
 
713
    freeObserverList();
 
714
  }
 
715
  return NS_OK;
 
716
}
 
717
 
 
718
PR_STATIC_CALLBACK(nsresult) NotifyObserver(const char *newpref, void *data)
 
719
{
 
720
  PrefCallbackData *pData = (PrefCallbackData *)data;
 
721
  nsPrefBranch *prefBranch = NS_STATIC_CAST(nsPrefBranch *, pData->pBranch);
 
722
 
 
723
  // remove any root this string may contain so as to not confuse the observer
 
724
  // by passing them something other than what they passed us as a topic
 
725
  PRUint32 len = prefBranch->GetRootLength();
 
726
  nsCAutoString suffix(newpref + len);  
 
727
 
 
728
  nsCOMPtr<nsIObserver> observer;
 
729
  if (pData->bIsWeakRef) {
 
730
    nsIWeakReference *weakRef = NS_STATIC_CAST(nsIWeakReference *, pData->pObserver);
 
731
    observer = do_QueryReferent(weakRef);
 
732
    if (!observer) {
 
733
      // this weak referenced observer went away, remove them from the list
 
734
      nsCOMPtr<nsIPrefBranchInternal> pbi = do_QueryInterface(pData->pBranch);
 
735
      if (pbi) {
 
736
        observer = NS_STATIC_CAST(nsIObserver *, pData->pObserver);
 
737
        pbi->RemoveObserver(newpref, observer);
 
738
      }
 
739
      return NS_OK;
 
740
    }
 
741
  } else
 
742
    observer = NS_STATIC_CAST(nsIObserver *, pData->pObserver);
 
743
 
 
744
  observer->Observe(pData->pBranch, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
 
745
                    NS_ConvertASCIItoUCS2(suffix).get());
 
746
  return NS_OK;
 
747
}
 
748
 
 
749
 
 
750
void nsPrefBranch::freeObserverList(void)
 
751
{
 
752
  const char *pref;
 
753
  PrefCallbackData *pCallback;
 
754
 
 
755
  if (mObservers) {
 
756
    // unregister the observers
 
757
    PRInt32 count;
 
758
 
 
759
    count = mObservers->Count();
 
760
    if (count > 0) {
 
761
      PRInt32 i;
 
762
      nsCAutoString domain;
 
763
      for (i = 0; i < count; ++i) {
 
764
        pCallback = (PrefCallbackData *)mObservers->ElementAt(i);
 
765
        if (pCallback) {
 
766
          mObserverDomains.CStringAt(i, domain);
 
767
          // We must pass a fully qualified preference name to remove the callback
 
768
          pref = getPrefName(domain.get()); // can't fail because domain must be valid
 
769
          // Remove this observer from our array so that nobody else can remove
 
770
          // what we're trying to remove right now.
 
771
          mObservers->ReplaceElementAt(nsnull, i);
 
772
          PREF_UnregisterCallback(pref, NotifyObserver, pCallback);
 
773
          NS_RELEASE(pCallback->pObserver);
 
774
          nsMemory::Free(pCallback);
 
775
        }
 
776
      }
 
777
 
 
778
      // now empty the observer domains array in bulk
 
779
      mObserverDomains.Clear();
 
780
    }
 
781
    delete mObservers;
 
782
    mObservers = 0;
 
783
  }
 
784
}
 
785
 
 
786
nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName, PRUnichar **return_buf)
 
787
{
 
788
  nsresult rv;
 
789
 
 
790
  // the default value contains a URL to a .properties file
 
791
    
 
792
  nsXPIDLCString propertyFileURL;
 
793
  rv = PREF_CopyCharPref(aPrefName, getter_Copies(propertyFileURL), PR_TRUE);
 
794
  if (NS_FAILED(rv))
 
795
    return rv;
 
796
    
 
797
  nsCOMPtr<nsIStringBundleService> bundleService =
 
798
      do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
 
799
  if (NS_FAILED(rv))
 
800
    return rv;
 
801
 
 
802
  nsCOMPtr<nsIStringBundle> bundle;
 
803
  rv = bundleService->CreateBundle(propertyFileURL,
 
804
                                   getter_AddRefs(bundle));
 
805
  if (NS_FAILED(rv))
 
806
    return rv;
 
807
 
 
808
  // string names are in unicode
 
809
  nsAutoString stringId;
 
810
  stringId.AssignWithConversion(aPrefName);
 
811
 
 
812
  return bundle->GetStringFromName(stringId.get(), return_buf);
 
813
}
 
814
 
 
815
const char *nsPrefBranch::getPrefName(const char *aPrefName)
 
816
{
 
817
  // for speed, avoid strcpy if we can:
 
818
  if (mPrefRoot.IsEmpty())
 
819
    return aPrefName;
 
820
 
 
821
  // isn't there a better way to do this? this is really kind of gross.
 
822
  mPrefRoot.Truncate(mPrefRootLength);
 
823
 
 
824
  // only append if anything to append
 
825
  if ((nsnull != aPrefName) && (*aPrefName != '\0'))
 
826
    mPrefRoot.Append(aPrefName);
 
827
 
 
828
  return mPrefRoot.get();
 
829
}
 
830
 
 
831
nsresult nsPrefBranch::getValidatedPrefName(const char *aPrefName, const char **_retval)
 
832
{
 
833
  static const char capabilityPrefix[] = "capability.";
 
834
 
 
835
  NS_ENSURE_ARG_POINTER(aPrefName);
 
836
  const char *fullPref = getPrefName(aPrefName);
 
837
 
 
838
  // now that we have the pref, check it against the ScriptSecurityManager
 
839
  if ((fullPref[0] == 'c') &&
 
840
    PL_strncmp(fullPref, capabilityPrefix, sizeof(capabilityPrefix)-1) == 0)
 
841
  {
 
842
    nsresult rv;
 
843
    nsCOMPtr<nsIScriptSecurityManager> secMan = 
 
844
             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
 
845
 
 
846
    if (NS_FAILED(rv))
 
847
      return NS_ERROR_FAILURE;
 
848
 
 
849
    PRBool enabled;
 
850
    rv = secMan->IsCapabilityEnabled("CapabilityPreferencesAccess", &enabled);
 
851
    if (NS_FAILED(rv) || !enabled)
 
852
      return NS_ERROR_FAILURE;
 
853
  }
 
854
 
 
855
  *_retval = fullPref;
 
856
  return NS_OK;
 
857
}
 
858
 
 
859
PR_STATIC_CALLBACK(PLDHashOperator)
 
860
pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh,
 
861
               PRUint32 i, void *arg)
 
862
{
 
863
  PrefHashEntry *he = NS_STATIC_CAST(PrefHashEntry*, heh);
 
864
  EnumerateData *d = NS_REINTERPRET_CAST(EnumerateData *, arg);
 
865
  if (PL_strncmp(he->key, d->parent, PL_strlen(d->parent)) == 0) {
 
866
    d->pref_list->AppendElement((void*)he->key);
 
867
  }
 
868
  return PL_DHASH_NEXT;
 
869
}
 
870
 
 
871
 
 
872
/*
 
873
 * nsISecurityPref methods
 
874
 *
 
875
 * Pref access without security check - these are here
 
876
 * to support nsScriptSecurityManager.
 
877
 * These functions are part of nsISecurityPref, not nsIPref.
 
878
 * **PLEASE** do not call these functions from elsewhere
 
879
 */
 
880
NS_IMETHODIMP nsPrefBranch::SecurityGetBoolPref(const char *pref, PRBool * return_val)
 
881
{
 
882
  return PREF_GetBoolPref(getPrefName(pref), return_val, PR_FALSE);
 
883
}
 
884
 
 
885
NS_IMETHODIMP nsPrefBranch::SecuritySetBoolPref(const char *pref, PRBool value)
 
886
{
 
887
  return PREF_SetBoolPref(getPrefName(pref), value);
 
888
}
 
889
 
 
890
NS_IMETHODIMP nsPrefBranch::SecurityGetCharPref(const char *pref, char ** return_buf)
 
891
{
 
892
  return PREF_CopyCharPref(getPrefName(pref), return_buf, PR_FALSE);
 
893
}
 
894
 
 
895
NS_IMETHODIMP nsPrefBranch::SecuritySetCharPref(const char *pref, const char* value)
 
896
{
 
897
  return PREF_SetCharPref(getPrefName(pref), value);
 
898
}
 
899
 
 
900
NS_IMETHODIMP nsPrefBranch::SecurityGetIntPref(const char *pref, PRInt32 * return_val)
 
901
{
 
902
  return PREF_GetIntPref(getPrefName(pref), return_val, PR_FALSE);
 
903
}
 
904
 
 
905
NS_IMETHODIMP nsPrefBranch::SecuritySetIntPref(const char *pref, PRInt32 value)
 
906
{
 
907
  return PREF_SetIntPref(getPrefName(pref), value);
 
908
}
 
909
 
 
910
NS_IMETHODIMP nsPrefBranch::SecurityClearUserPref(const char *pref_name)
 
911
{
 
912
  return PREF_ClearUserPref(getPrefName(pref_name));
 
913
}
 
914
 
 
915
//----------------------------------------------------------------------------
 
916
// nsPrefLocalizedString
 
917
//----------------------------------------------------------------------------
 
918
 
 
919
nsPrefLocalizedString::nsPrefLocalizedString()
 
920
{
 
921
}
 
922
 
 
923
nsPrefLocalizedString::~nsPrefLocalizedString()
 
924
{
 
925
}
 
926
 
 
927
 
 
928
/*
 
929
 * nsISupports Implementation
 
930
 */
 
931
 
 
932
NS_IMPL_THREADSAFE_ADDREF(nsPrefLocalizedString)
 
933
NS_IMPL_THREADSAFE_RELEASE(nsPrefLocalizedString)
 
934
 
 
935
NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString)
 
936
    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefLocalizedString)
 
937
    NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString)
 
938
    NS_INTERFACE_MAP_ENTRY(nsISupportsString)
 
939
NS_INTERFACE_MAP_END
 
940
 
 
941
nsresult nsPrefLocalizedString::Init()
 
942
{
 
943
  nsresult rv;
 
944
  mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
 
945
 
 
946
  return rv;
 
947
}
 
948
 
 
949
NS_IMETHODIMP
 
950
nsPrefLocalizedString::GetData(PRUnichar** _retval)
 
951
{
 
952
  nsAutoString data;
 
953
 
 
954
  nsresult rv = GetData(data);
 
955
  if (NS_FAILED(rv))
 
956
    return rv;
 
957
  
 
958
  *_retval = ToNewUnicode(data);
 
959
  if (!*_retval)
 
960
    return NS_ERROR_OUT_OF_MEMORY;
 
961
 
 
962
  return NS_OK;
 
963
}
 
964
 
 
965
NS_IMETHODIMP
 
966
nsPrefLocalizedString::SetData(const PRUnichar *aData)
 
967
{
 
968
  return SetData(nsDependentString(aData));
 
969
}
 
970
 
 
971
NS_IMETHODIMP
 
972
nsPrefLocalizedString::SetDataWithLength(PRUint32 aLength,
 
973
                                         const PRUnichar* aData)
 
974
{
 
975
  return SetData(Substring(aData, aData + aLength));
 
976
}
 
977
 
 
978
//----------------------------------------------------------------------------
 
979
// nsRelativeFilePref
 
980
//----------------------------------------------------------------------------
 
981
 
 
982
NS_IMPL_THREADSAFE_ISUPPORTS1(nsRelativeFilePref, nsIRelativeFilePref)
 
983
 
 
984
nsRelativeFilePref::nsRelativeFilePref()
 
985
{
 
986
}
 
987
 
 
988
nsRelativeFilePref::~nsRelativeFilePref()
 
989
{
 
990
}
 
991
 
 
992
NS_IMETHODIMP nsRelativeFilePref::GetFile(nsILocalFile * *aFile)
 
993
{
 
994
    NS_ENSURE_ARG_POINTER(aFile);
 
995
    *aFile = mFile;
 
996
    NS_IF_ADDREF(*aFile);
 
997
    return *aFile ? NS_OK : NS_ERROR_NULL_POINTER;
 
998
}
 
999
 
 
1000
NS_IMETHODIMP nsRelativeFilePref::SetFile(nsILocalFile * aFile)
 
1001
{
 
1002
    mFile = aFile;
 
1003
    return NS_OK;
 
1004
}
 
1005
 
 
1006
NS_IMETHODIMP nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey)
 
1007
{
 
1008
    aRelativeToKey.Assign(mRelativeToKey);
 
1009
    return NS_OK;
 
1010
}
 
1011
 
 
1012
NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey)
 
1013
{
 
1014
    mRelativeToKey.Assign(aRelativeToKey);
 
1015
    return NS_OK;
 
1016
}