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

« back to all changes in this revision

Viewing changes to mozilla/uriloader/exthandler/mac/nsInternetConfigService.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
 *   Steve Dagley <sdagley@netscape.com>
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the NPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the NPL, the GPL or the LGPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
#include "nsInternetConfigService.h"
 
40
#include "nsCOMPtr.h"
 
41
#include "nsIMIMEInfo.h"
 
42
#include "nsMIMEInfoMac.h"
 
43
#include "nsAutoPtr.h"
 
44
#include "nsIFactory.h"
 
45
#include "nsIComponentManager.h"
 
46
#include "nsIURL.h"
 
47
#include "nsXPIDLString.h"
 
48
#include "nsReadableUtils.h"
 
49
#include "nsString.h"
 
50
#include "nsCRT.h"
 
51
#include "nsILocalFileMac.h"
 
52
#include "nsMimeTypes.h"
 
53
#include <TextUtils.h>
 
54
#include <CodeFragments.h>
 
55
#include <Processes.h>
 
56
#include <Gestalt.h>
 
57
#include <CFURL.h>
 
58
#include <Finder.h>
 
59
#include <LaunchServices.h>
 
60
 
 
61
 
 
62
// helper converter function.....
 
63
static void ConvertCharStringToStr255(const char* inString, Str255& outString)
 
64
{
 
65
  if (inString == NULL)
 
66
    return;
 
67
  
 
68
  PRInt32 len = strlen(inString);
 
69
  NS_ASSERTION(len <= 255 , " String is too big");
 
70
  if (len> 255)
 
71
  {
 
72
    len = 255;
 
73
  }
 
74
  memcpy(&outString[1], inString, len);
 
75
  outString[0] = len;
 
76
}
 
77
 
 
78
/* Define Class IDs */
 
79
 
 
80
nsInternetConfigService::nsInternetConfigService()
 
81
{
 
82
  long  version;
 
83
  OSErr err;
 
84
  mRunningOSX = ((err = ::Gestalt(gestaltSystemVersion, &version)) == noErr && version >= 0x00001000);
 
85
  mRunningJaguar = (err == noErr && version >= 0x00001020);
 
86
}
 
87
 
 
88
nsInternetConfigService::~nsInternetConfigService()
 
89
{
 
90
}
 
91
 
 
92
 
 
93
/*
 
94
 * Implement the nsISupports methods...
 
95
 */
 
96
NS_IMPL_ISUPPORTS1(nsInternetConfigService, nsIInternetConfigService)
 
97
 
 
98
// void LaunchURL (in string url);
 
99
// Given a url string, call ICLaunchURL using url
 
100
// Under OS X use LaunchServices instead of IC
 
101
NS_IMETHODIMP nsInternetConfigService::LaunchURL(const char *url)
 
102
{
 
103
  nsresult rv = NS_ERROR_FAILURE;
 
104
  
 
105
#if TARGET_CARBON
 
106
  if (mRunningOSX && ((UInt32)LSOpenCFURLRef != (UInt32)kUnresolvedCFragSymbolAddress))
 
107
  {
 
108
    CFURLRef myURLRef = ::CFURLCreateWithBytes(
 
109
                                              kCFAllocatorDefault,
 
110
                                              (const UInt8*)url,
 
111
                                              strlen(url),
 
112
                                              kCFStringEncodingUTF8, NULL);
 
113
    if (myURLRef)
 
114
    {
 
115
      rv = ::LSOpenCFURLRef(myURLRef, NULL);
 
116
      ::CFRelease(myURLRef);
 
117
    }
 
118
  }
 
119
  else
 
120
#endif
 
121
  {
 
122
    size_t len = strlen(url);
 
123
    long selStart = 0, selEnd = len;
 
124
    ICInstance inst = nsInternetConfig::GetInstance();
 
125
    
 
126
    if (inst)
 
127
    {
 
128
      if (::ICLaunchURL(inst, "\p", (Ptr)url, (long)len, &selStart, &selEnd) == noErr)
 
129
        rv = NS_OK;
 
130
    }
 
131
  }
 
132
  return rv;
 
133
}
 
134
 
 
135
// boolean HasMappingForMIMEType (in string mimetype);
 
136
// given a mime type, search Internet Config database for a mapping for that mime type
 
137
NS_IMETHODIMP nsInternetConfigService::HasMappingForMIMEType(const char *mimetype, PRBool *_retval)
 
138
{
 
139
  ICMapEntry entry;
 
140
  nsresult rv = GetMappingForMIMEType(mimetype, nsnull, &entry);
 
141
  if (rv == noErr)
 
142
    *_retval = PR_TRUE;
 
143
  else
 
144
    *_retval = PR_FALSE;
 
145
  return rv;
 
146
}
 
147
 
 
148
/* boolean hasProtocalHandler (in string protocol); */
 
149
// returns NS_ERROR_NOT_AVAILABLE if the current application is registered for as the
 
150
// protocol handler for protocol
 
151
NS_IMETHODIMP nsInternetConfigService::HasProtocolHandler(const char *protocol, PRBool *_retval)
 
152
{
 
153
  *_retval = PR_FALSE;            // Presume failure
 
154
  nsresult rv = NS_ERROR_FAILURE; // Ditto
 
155
  
 
156
#if TARGET_CARBON
 
157
  // Use LaunchServices directly when we're running under OS X to avoid the problem of some protocols
 
158
  // apparently not being reflected into the IC mappings (webcal for one).  Even better it seems
 
159
  // LaunchServices under 10.1.x will often fail to find an app when using LSGetApplicationForURL
 
160
  // so we only use it for 10.2 or later.
 
161
  
 
162
  // Since protocol comes in with _just_ the protocol we have to add a ':' to the end of it or
 
163
  // LaunchServices will be very unhappy with the CFURLRef created from it (crashes trying to look
 
164
  // up a handler for it with LSGetApplicationForURL, at least under 10.2.1)
 
165
  if (mRunningJaguar)
 
166
  {
 
167
    nsCAutoString scheme(protocol);
 
168
    scheme += ":";
 
169
    CFURLRef myURLRef = ::CFURLCreateWithBytes(
 
170
                                                kCFAllocatorDefault,
 
171
                                                (const UInt8 *)scheme.get(),
 
172
                                                scheme.Length(),
 
173
                                                kCFStringEncodingUTF8, NULL);
 
174
    if (myURLRef)
 
175
    {
 
176
      FSRef appFSRef;
 
177
      
 
178
      if (::LSGetApplicationForURL(myURLRef, kLSRolesAll, &appFSRef, NULL) == noErr)
 
179
      { // Now see if the FSRef for the found app == the running app
 
180
        ProcessSerialNumber psn;
 
181
        if (::GetCurrentProcess(&psn) == noErr)
 
182
        {
 
183
          FSRef runningAppFSRef;
 
184
          if (::GetProcessBundleLocation(&psn, &runningAppFSRef) == noErr)
 
185
          {
 
186
            if (::FSCompareFSRefs(&appFSRef, &runningAppFSRef) == noErr)
 
187
            { // Oops, the current app is the handler which would cause infinite recursion
 
188
              rv = NS_ERROR_NOT_AVAILABLE;
 
189
            }
 
190
            else
 
191
            {
 
192
              *_retval = PR_TRUE;
 
193
              rv = NS_OK;
 
194
            }
 
195
          }
 
196
        }
 
197
      }
 
198
      ::CFRelease(myURLRef);
 
199
    }
 
200
  }
 
201
  else
 
202
#endif
 
203
  {
 
204
    // look for IC pref "\pHelperļæ½<protocol>"
 
205
    Str255 pref = kICHelper;
 
206
 
 
207
    if (nsCRT::strlen(protocol) > 248)
 
208
      rv = NS_ERROR_OUT_OF_MEMORY;
 
209
    else
 
210
    {
 
211
      memcpy(pref + pref[0] + 1, protocol, nsCRT::strlen(protocol));
 
212
      pref[0] = pref[0] + nsCRT::strlen(protocol);
 
213
      
 
214
      ICInstance instance = nsInternetConfig::GetInstance();
 
215
      if (instance)
 
216
      {
 
217
        OSStatus  err;
 
218
        ICAttr    junk;
 
219
        ICAppSpec spec;
 
220
        long      ioSize = sizeof(ICAppSpec);
 
221
        err = ::ICGetPref(instance, pref, &junk, (void *)&spec, &ioSize);
 
222
      
 
223
        if (err == noErr)
 
224
        {
 
225
          // check if registered protocol helper is us
 
226
          // if so, return PR_FALSE because we'll go into infinite recursion
 
227
          // continually launching back into ourselves
 
228
          ProcessSerialNumber psn;
 
229
          OSErr oserr = ::GetCurrentProcess(&psn);
 
230
          if (oserr == noErr)
 
231
          {
 
232
            ProcessInfoRec info;
 
233
            info.processInfoLength = sizeof(ProcessInfoRec);
 
234
            info.processName = nsnull;
 
235
            info.processAppSpec = nsnull;
 
236
            err = ::GetProcessInformation(&psn, &info);
 
237
            if (err == noErr)
 
238
            {
 
239
              if (info.processSignature != spec.fCreator)
 
240
              {
 
241
                *_retval = PR_TRUE;
 
242
                rv = NS_OK;
 
243
              }
 
244
              else
 
245
                rv = NS_ERROR_NOT_AVAILABLE;
 
246
            }
 
247
          }
 
248
        }
 
249
      }
 
250
    }
 
251
  }
 
252
  return rv;
 
253
}
 
254
 
 
255
// This method does the dirty work of traipsing through IC mappings database
 
256
// looking for a mapping for mimetype
 
257
nsresult nsInternetConfigService::GetMappingForMIMEType(const char *mimetype, const char *fileextension, ICMapEntry *entry)
 
258
{
 
259
  ICInstance  inst = nsInternetConfig::GetInstance();
 
260
  OSStatus    err = noErr;
 
261
  ICAttr      attr;
 
262
  Handle      prefH;
 
263
  PRBool      domimecheck = PR_TRUE;
 
264
  PRBool      gotmatch = PR_FALSE;
 
265
  ICMapEntry  ent;
 
266
  
 
267
  // if mime type is "unknown" or "octet stream" *AND* we have a file extension,
 
268
  // then disable match on mime type
 
269
  if (((nsCRT::strcasecmp(mimetype, UNKNOWN_CONTENT_TYPE) == 0) ||
 
270
       (nsCRT::strcasecmp(mimetype, APPLICATION_OCTET_STREAM) == 0)) &&
 
271
       fileextension)
 
272
    domimecheck = PR_FALSE;
 
273
  
 
274
  entry->totalLength = 0;
 
275
  if (inst)
 
276
  {
 
277
    err = ::ICBegin(inst, icReadOnlyPerm);
 
278
    if (err == noErr)
 
279
    {
 
280
      prefH = ::NewHandle(2048); // picked 2048 out of thin air
 
281
      if (prefH)
 
282
      {
 
283
        err = ::ICFindPrefHandle(inst, kICMapping, &attr, prefH);
 
284
        if (err == noErr)
 
285
        {
 
286
          long count;
 
287
          err = ::ICCountMapEntries(inst, prefH, &count);
 
288
          if (err == noErr)
 
289
          {
 
290
            long pos;
 
291
            for (long i = 1; i <= count; ++i)
 
292
            {
 
293
              err = ::ICGetIndMapEntry(inst, prefH, i, &pos, &ent);
 
294
              if (err == noErr)
 
295
              {
 
296
                // first, do mime type check
 
297
                if (domimecheck)
 
298
                {
 
299
                  nsCAutoString temp((char *)&ent.MIMEType[1], (int)ent.MIMEType[0]);
 
300
                  if (!temp.EqualsIgnoreCase(mimetype))
 
301
                  {
 
302
                    // we need to do mime check, and check failed
 
303
                    // nothing here to see, move along
 
304
                    continue;
 
305
                  }
 
306
                }
 
307
                if (fileextension)
 
308
                {
 
309
                  // if fileextension was passed in, compare that also
 
310
                  if (ent.extension[0]) // check for non-empty pascal string
 
311
                  {
 
312
                    nsCAutoString temp((char *)&ent.extension[1], (int)ent.extension[0]);
 
313
                    if (temp.EqualsIgnoreCase(fileextension))
 
314
                    {
 
315
                      // mime type and file extension match, we're outta here
 
316
                      gotmatch = PR_TRUE;
 
317
                      // copy over ICMapEntry
 
318
                      *entry = ent;
 
319
                      break;
 
320
                    }
 
321
                  }
 
322
                }
 
323
                else if(domimecheck)
 
324
                {
 
325
                  // at this point, we've got our match because
 
326
                  // domimecheck is true, the mime strings match, and fileextension isn't passed in
 
327
                  // bad thing is we'll stop on first match, but what can you do?
 
328
                  gotmatch = PR_TRUE;
 
329
                  // copy over ICMapEntry
 
330
                  *entry = ent;
 
331
                  break;
 
332
                }
 
333
              }
 
334
            }
 
335
          }
 
336
        }
 
337
        ::DisposeHandle(prefH);
 
338
      }
 
339
      else
 
340
      {
 
341
        err = memFullErr;
 
342
      }
 
343
      err = ::ICEnd(inst);
 
344
      if (err == noErr && gotmatch == PR_FALSE)
 
345
      {
 
346
        err = fnfErr; // return SOME kind of error
 
347
      }
 
348
    }
 
349
  }
 
350
  
 
351
  if (err != noErr)
 
352
    return NS_ERROR_FAILURE;
 
353
  else
 
354
    return NS_OK;
 
355
}
 
356
 
 
357
nsresult nsInternetConfigService::FillMIMEInfoForICEntry(ICMapEntry& entry, nsIMIMEInfo ** mimeinfo)
 
358
{
 
359
  // create a mime info object and we'll fill it in based on the values from IC mapping entry
 
360
  nsresult  rv = NS_OK;
 
361
  nsRefPtr<nsMIMEInfoMac> info (new nsMIMEInfoMac());
 
362
  if (info)
 
363
  {
 
364
    nsCAutoString mimetype ((char *)&entry.MIMEType[1], entry.MIMEType[0]);
 
365
    // check if entry.MIMEType is empty, if so, set mime type to APPLICATION_OCTET_STREAM
 
366
    if (entry.MIMEType[0])
 
367
      info->SetMIMEType(mimetype.get());
 
368
    else
 
369
    { // The IC mappings seem to not be very agressive about determining the mime type if
 
370
      // all we have is a type or creator code.  This is a bandaid approach for when we
 
371
      // get a file of type 'TEXT' with no mime type mapping so that we'll display the
 
372
      // file rather than trying to download it.
 
373
      if (entry.fileType == 'TEXT')
 
374
        info->SetMIMEType(TEXT_PLAIN);
 
375
      else
 
376
        info->SetMIMEType(APPLICATION_OCTET_STREAM);
 
377
    }
 
378
    
 
379
    // convert entry.extension which is a Str255 
 
380
    // don't forget to remove the '.' in front of the file extension....
 
381
    nsCAutoString temp((char *)&entry.extension[2], entry.extension[0] > 0 ? (int)entry.extension[0]-1 : 0);
 
382
    info->AppendExtension(temp.get());
 
383
    info->SetMacType(entry.fileType);
 
384
    info->SetMacCreator(entry.fileCreator);
 
385
    temp.Assign((char *) &entry.entryName[1], entry.entryName[0]);
 
386
    info->SetDescription(NS_ConvertASCIItoUCS2(temp.get()).get());
 
387
    
 
388
    temp.Assign((char *) &entry.postAppName[1], entry.postAppName[0]);
 
389
    info->SetDefaultDescription(NS_ConvertASCIItoUCS2(temp.get()).get());
 
390
    
 
391
    if (entry.flags & kICMapPostMask)
 
392
    {
 
393
      // there is a post processor app
 
394
      info->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
 
395
      nsCOMPtr<nsILocalFileMac> file (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
 
396
      if (file)
 
397
      {
 
398
        rv = file->InitToAppWithCreatorCode(entry.postCreator);
 
399
        if (rv == NS_OK)
 
400
        {
 
401
          nsCOMPtr<nsIFile> nsfile = do_QueryInterface(file, &rv);
 
402
          if (rv == NS_OK)
 
403
            info->SetDefaultApplication(nsfile);
 
404
        }
 
405
      }
 
406
    }
 
407
    else
 
408
    {
 
409
      // there isn't a post processor app so set the preferred action to be save to disk.
 
410
      info->SetPreferredAction(nsIMIMEInfo::saveToDisk);
 
411
    }
 
412
    
 
413
    *mimeinfo = info;
 
414
    NS_IF_ADDREF(*mimeinfo);
 
415
  }
 
416
  else // we failed to allocate the info object...
 
417
    rv = NS_ERROR_FAILURE;
 
418
   
 
419
  return rv;
 
420
}
 
421
 
 
422
/* void FillInMIMEInfo (in string mimetype, in string fileExtension, out nsIMIMEInfo mimeinfo); */
 
423
NS_IMETHODIMP nsInternetConfigService::FillInMIMEInfo(const char *mimetype, const char * aFileExtension, nsIMIMEInfo **mimeinfo)
 
424
{
 
425
  nsresult    rv;
 
426
  ICMapEntry  entry;
 
427
  
 
428
  NS_ENSURE_ARG_POINTER(mimeinfo);
 
429
  *mimeinfo = nsnull;
 
430
 
 
431
  if (aFileExtension)
 
432
  {
 
433
    nsCAutoString fileExtension;
 
434
    fileExtension.Assign(".");  
 
435
    fileExtension.Append(aFileExtension);
 
436
    rv = GetMappingForMIMEType(mimetype, fileExtension.get(), &entry);
 
437
  }
 
438
  else
 
439
  {
 
440
    rv = GetMappingForMIMEType(mimetype, nsnull, &entry);
 
441
  }
 
442
  
 
443
  if (rv == NS_OK)
 
444
    rv = FillMIMEInfoForICEntry(entry, mimeinfo);
 
445
  else
 
446
    rv = NS_ERROR_FAILURE;
 
447
 
 
448
  return rv;
 
449
}
 
450
 
 
451
NS_IMETHODIMP nsInternetConfigService::GetMIMEInfoFromExtension(const char *aFileExt, nsIMIMEInfo **_retval)
 
452
{
 
453
  nsresult    rv = NS_ERROR_FAILURE;
 
454
  ICInstance  instance = nsInternetConfig::GetInstance();
 
455
  if (instance)
 
456
  {
 
457
    nsCAutoString filename("foobar.");
 
458
    filename += aFileExt;
 
459
    Str255  pFileName;
 
460
    ConvertCharStringToStr255(filename.get(), pFileName);
 
461
    ICMapEntry  entry;
 
462
    OSStatus  err = ::ICMapFilename(instance, pFileName, &entry);
 
463
    if (err == noErr)
 
464
    {
 
465
      rv = FillMIMEInfoForICEntry(entry, _retval);
 
466
    }
 
467
  }   
 
468
  return rv;
 
469
}
 
470
 
 
471
 
 
472
NS_IMETHODIMP nsInternetConfigService::GetMIMEInfoFromTypeCreator(PRUint32 aType, PRUint32 aCreator, const char *aFileExt, nsIMIMEInfo **_retval)
 
473
{
 
474
  nsresult    rv = NS_ERROR_FAILURE;
 
475
  ICInstance  instance = nsInternetConfig::GetInstance();
 
476
  if (instance)
 
477
  {
 
478
    nsCAutoString filename("foobar.");
 
479
    filename += aFileExt;
 
480
    Str255  pFileName;
 
481
    ConvertCharStringToStr255(filename.get(), pFileName);
 
482
    ICMapEntry  entry;
 
483
    OSStatus  err = ::ICMapTypeCreator(instance, aType, aCreator, pFileName, &entry);
 
484
    if (err == noErr)
 
485
      rv = FillMIMEInfoForICEntry(entry,_retval);
 
486
  }
 
487
  return rv;
 
488
}
 
489
 
 
490
 
 
491
NS_IMETHODIMP nsInternetConfigService::GetFileMappingFlags(FSSpec* fsspec, PRBool lookupByExtensionFirst, PRInt32 *_retval)
 
492
{
 
493
  nsresult  rv = NS_ERROR_FAILURE;
 
494
  OSStatus  err = noErr;
 
495
 
 
496
  NS_ENSURE_ARG(_retval);
 
497
  *_retval = -1;
 
498
  
 
499
  ICInstance instance = nsInternetConfig::GetInstance();
 
500
  if (instance)
 
501
  {
 
502
    ICMapEntry  entry;
 
503
    
 
504
    if (lookupByExtensionFirst)
 
505
      err = ::ICMapFilename(instance, fsspec->name, &entry);
 
506
  
 
507
    if (!lookupByExtensionFirst || err != noErr)
 
508
    {
 
509
      FInfo info;
 
510
      err = FSpGetFInfo(fsspec, &info);
 
511
      if (err == noErr)
 
512
        err = ::ICMapTypeCreator(instance, info.fdType, info.fdCreator, fsspec->name, &entry);
 
513
    }
 
514
 
 
515
    if (err == noErr)
 
516
      *_retval = entry.flags;
 
517
     
 
518
     rv = NS_OK;
 
519
  }
 
520
  return rv;
 
521
}
 
522
 
 
523
 
 
524
/* void GetDownloadFolder (out FSSpec fsspec); */
 
525
NS_IMETHODIMP nsInternetConfigService::GetDownloadFolder(FSSpec *fsspec)
 
526
{
 
527
  ICInstance  inst = nsInternetConfig::GetInstance();
 
528
  OSStatus    err;
 
529
  Handle      prefH;
 
530
  nsresult    rv = NS_ERROR_FAILURE;
 
531
  
 
532
  NS_ENSURE_ARG_POINTER(fsspec);
 
533
  
 
534
  if (inst)
 
535
  {
 
536
    err = ::ICBegin(inst, icReadOnlyPerm);
 
537
    if (err == noErr)
 
538
    {
 
539
      prefH = ::NewHandle(256); // ICFileSpec ~= 112 bytes + variable, 256 bytes hopefully is sufficient
 
540
      if (prefH)
 
541
      {
 
542
        ICAttr  attr;
 
543
        err = ::ICFindPrefHandle(inst, kICDownloadFolder, &attr, prefH);
 
544
        if (err == noErr)
 
545
        {
 
546
          err = ::Munger(prefH, 0, NULL, kICFileSpecHeaderSize, (Ptr)-1, 0);
 
547
          if (err == noErr)
 
548
          {
 
549
            Boolean wasChanged;
 
550
            err = ::ResolveAlias(NULL, (AliasHandle)prefH, fsspec, &wasChanged);
 
551
            if (err == noErr)
 
552
            {
 
553
              rv = NS_OK;
 
554
            }
 
555
            else
 
556
            { // ResolveAlias for the DownloadFolder failed - try grabbing the FSSpec
 
557
              err = ::ICFindPrefHandle(inst, kICDownloadFolder, &attr, prefH);
 
558
              if (err == noErr)
 
559
              { // Use FSMakeFSSpec to verify the saved FSSpec is still valid
 
560
                FSSpec  tempSpec = (*(ICFileSpecHandle)prefH)->fss;
 
561
                err = ::FSMakeFSSpec(tempSpec.vRefNum, tempSpec.parID, tempSpec.name, fsspec);
 
562
                if (err == noErr)
 
563
                  rv = NS_OK;
 
564
              }
 
565
            }
 
566
          }
 
567
        }
 
568
        // Best not to leave that handle laying around
 
569
        DisposeHandle(prefH);
 
570
      }
 
571
      err = ::ICEnd(inst);
 
572
    }
 
573
  }
 
574
  return rv;
 
575
}
 
576
 
 
577
nsresult nsInternetConfigService::GetICKeyPascalString(PRUint32 inIndex, const unsigned char*& outICKey)
 
578
{
 
579
  nsresult  rv = NS_OK;
 
580
 
 
581
  switch (inIndex)
 
582
  {
 
583
    case eICColor_WebBackgroundColour: outICKey = kICWebBackgroundColour; break;
 
584
    case eICColor_WebReadColor:        outICKey = kICWebReadColor;        break;
 
585
    case eICColor_WebTextColor:        outICKey = kICWebTextColor;        break;
 
586
    case eICColor_WebUnreadColor:      outICKey = kICWebUnreadColor;      break;
 
587
 
 
588
    case eICBoolean_WebUnderlineLinks: outICKey = kICWebUnderlineLinks;  break;
 
589
    case eICBoolean_UseFTPProxy:       outICKey = kICUseFTPProxy;        break;
 
590
    case eICBoolean_UsePassiveFTP:     outICKey = kICUsePassiveFTP;      break;
 
591
    case eICBoolean_UseHTTPProxy:      outICKey = kICUseHTTPProxy;       break;
 
592
    case eICBoolean_NewMailDialog:     outICKey = kICNewMailDialog;      break;
 
593
    case eICBoolean_NewMailFlashIcon:  outICKey = kICNewMailFlashIcon;   break;
 
594
    case eICBoolean_NewMailPlaySound:  outICKey = kICNewMailPlaySound;   break;
 
595
    case eICBoolean_UseGopherProxy:    outICKey = kICUseGopherProxy;     break;
 
596
    case eICBoolean_UseSocks:          outICKey = kICUseSocks;           break;
 
597
 
 
598
    case eICString_WWWHomePage:        outICKey = kICWWWHomePage;        break;
 
599
    case eICString_WebSearchPagePrefs: outICKey = kICWebSearchPagePrefs; break;
 
600
    case eICString_MacSearchHost:      outICKey = kICMacSearchHost;      break;
 
601
    case eICString_FTPHost:            outICKey = kICFTPHost;            break;
 
602
    case eICString_FTPProxyUser:       outICKey = kICFTPProxyUser;       break;
 
603
    case eICString_FTPProxyAccount:    outICKey = kICFTPProxyAccount;    break;
 
604
    case eICString_FTPProxyHost:       outICKey = kICFTPProxyHost;       break;
 
605
    case eICString_FTPProxyPassword:   outICKey = kICFTPProxyPassword;   break;
 
606
    case eICString_HTTPProxyHost:      outICKey = kICHTTPProxyHost;      break;
 
607
    case eICString_LDAPSearchbase:     outICKey = kICLDAPSearchbase;     break;
 
608
    case eICString_LDAPServer:         outICKey = kICLDAPServer;         break;
 
609
    case eICString_SMTPHost:           outICKey = kICSMTPHost;           break;
 
610
    case eICString_Email:              outICKey = kICEmail;              break;
 
611
    case eICString_MailAccount:        outICKey = kICMailAccount;        break;
 
612
    case eICString_MailPassword:       outICKey = kICMailPassword;       break;
 
613
    case eICString_NewMailSoundName:   outICKey = kICNewMailSoundName;   break;
 
614
    case eICString_NNTPHost:           outICKey = kICNNTPHost;           break;
 
615
    case eICString_NewsAuthUsername:   outICKey = kICNewsAuthUsername;   break;
 
616
    case eICString_NewsAuthPassword:   outICKey = kICNewsAuthPassword;   break;
 
617
    case eICString_InfoMacPreferred:   outICKey = kICInfoMacPreferred;   break;
 
618
    case eICString_Organization:       outICKey = kICOrganization;       break;
 
619
    case eICString_QuotingString:      outICKey = kICQuotingString;      break;
 
620
    case eICString_RealName:           outICKey = kICRealName;           break;
 
621
    case eICString_FingerHost:         outICKey = kICFingerHost;         break;
 
622
    case eICString_GopherHost:         outICKey = kICGopherHost;         break;
 
623
    case eICString_GopherProxy:        outICKey = kICGopherProxy;        break;
 
624
    case eICString_SocksHost:          outICKey = kICSocksHost;          break;
 
625
    case eICString_TelnetHost:         outICKey = kICTelnetHost;         break;
 
626
    case eICString_IRCHost:            outICKey = kICIRCHost;            break;
 
627
    case eICString_UMichPreferred:     outICKey = kICUMichPreferred;     break;
 
628
    case eICString_WAISGateway:        outICKey = kICWAISGateway;        break;
 
629
    case eICString_WhoisHost:          outICKey = kICWhoisHost;          break;
 
630
    case eICString_PhHost:             outICKey = kICPhHost;             break;
 
631
    case eICString_NTPHost:            outICKey = kICNTPHost;            break;
 
632
    case eICString_ArchiePreferred:    outICKey = kICArchiePreferred;    break;
 
633
    
 
634
    case eICText_MailHeaders:          outICKey = kICMailHeaders;        break;
 
635
    case eICText_Signature:            outICKey = kICSignature;          break;
 
636
    case eICText_NewsHeaders:          outICKey = kICNewsHeaders;        break;
 
637
    case eICText_SnailMailAddress:     outICKey = kICSnailMailAddress;   break;
 
638
    case eICText_Plan:                 outICKey = kICPlan;               break;
 
639
 
 
640
    default:
 
641
      rv = NS_ERROR_INVALID_ARG;
 
642
  }
 
643
  return rv;
 
644
}
 
645
 
 
646
 
 
647
nsresult nsInternetConfigService::GetICPreference(PRUint32 inKey, 
 
648
                                                  void *outData, long *ioSize)
 
649
{
 
650
  const unsigned char *icKey;
 
651
  nsresult  rv = GetICKeyPascalString(inKey, icKey);
 
652
  if (rv == NS_OK)
 
653
  {
 
654
    ICInstance  instance = nsInternetConfig::GetInstance();
 
655
    if (instance)
 
656
    {
 
657
      OSStatus  err;
 
658
      ICAttr    junk;
 
659
      err = ::ICGetPref(instance, icKey, &junk, outData, ioSize);
 
660
      if (err != noErr)
 
661
        rv = NS_ERROR_UNEXPECTED;
 
662
    }
 
663
    else
 
664
      rv = NS_ERROR_FAILURE;
 
665
  }
 
666
  return rv;
 
667
}
 
668
 
 
669
 
 
670
NS_IMETHODIMP nsInternetConfigService::GetString(PRUint32 inKey, nsACString& value)
 
671
{
 
672
  long      size = 256;
 
673
  char      buffer[256];
 
674
  nsresult  rv = GetICPreference(inKey, (void *)&buffer, &size);
 
675
  if (rv == NS_OK)
 
676
  {
 
677
    if (size == 0)
 
678
    {
 
679
      value = "";
 
680
      rv = NS_ERROR_UNEXPECTED;
 
681
    }
 
682
    else
 
683
    { // Buffer is a Pascal string so adjust for length byte when assigning
 
684
      value.Assign(&buffer[1], (unsigned char)buffer[0]);
 
685
    }
 
686
  }
 
687
  return rv;
 
688
}
 
689
 
 
690
 
 
691
NS_IMETHODIMP nsInternetConfigService::GetColor(PRUint32 inKey, PRUint32 *outColor)
 
692
{
 
693
// We're 'borrowing' this macro from nscolor.h so that uriloader doesn't depend on gfx.
 
694
// Make a color out of r,g,b values. This assumes that the r,g,b values are
 
695
// properly constrained to 0-255. This also assumes that a is 255.
 
696
 
 
697
  #define MAKE_NS_RGB(_r,_g,_b) \
 
698
    ((PRUint32) ((255 << 24) | ((_b)<<16) | ((_g)<<8) | (_r)))
 
699
 
 
700
  RGBColor  buffer;
 
701
  long      size = sizeof(RGBColor);
 
702
  nsresult  rv = GetICPreference(inKey, &buffer, &size);
 
703
  if (rv == NS_OK)
 
704
  {
 
705
    if (size != sizeof(RGBColor))
 
706
    { // default to white if we didn't get the right size
 
707
      *outColor = MAKE_NS_RGB(0xff, 0xff, 0xff);
 
708
    }
 
709
    else
 
710
    { // convert to a web color
 
711
      *outColor = MAKE_NS_RGB(buffer.red >> 8, buffer.green >> 8, buffer.blue >> 8);
 
712
    }
 
713
  }
 
714
  return rv;
 
715
}
 
716
 
 
717
 
 
718
NS_IMETHODIMP nsInternetConfigService::GetBoolean(PRUint32 inKey, PRBool *outFlag)
 
719
{
 
720
  Boolean   buffer;
 
721
  long      size = sizeof(Boolean);
 
722
  nsresult  rv = GetICPreference(inKey, (void *)&buffer, &size);
 
723
  if (rv == NS_OK)
 
724
  {
 
725
    if ((size_t)size < sizeof(Boolean))
 
726
      *outFlag = PR_FALSE;  // default to false if we didn't get the right amount of data
 
727
    else
 
728
      *outFlag = buffer;
 
729
  }
 
730
  return rv;
 
731
}