Back to index

lightning-sunbird  0.9+nobinonly
nsInternetConfigService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Steve Dagley <sdagley@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsInternetConfigService.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsIMIMEInfo.h"
00042 #include "nsMIMEInfoMac.h"
00043 #include "nsAutoPtr.h"
00044 #include "nsIFactory.h"
00045 #include "nsIComponentManager.h"
00046 #include "nsIURL.h"
00047 #include "nsXPIDLString.h"
00048 #include "nsReadableUtils.h"
00049 #include "nsString.h"
00050 #include "nsCRT.h"
00051 #include "nsILocalFileMac.h"
00052 #include "nsMimeTypes.h"
00053 #include <TextUtils.h>
00054 #include <CodeFragments.h>
00055 #include <Processes.h>
00056 #include <Gestalt.h>
00057 #include <CFURL.h>
00058 #include <Finder.h>
00059 #include <LaunchServices.h>
00060 
00061 
00062 // helper converter function.....
00063 static void ConvertCharStringToStr255(const char* inString, Str255& outString)
00064 {
00065   if (inString == NULL)
00066     return;
00067   
00068   PRInt32 len = strlen(inString);
00069   NS_ASSERTION(len <= 255 , " String is too big");
00070   if (len> 255)
00071   {
00072     len = 255;
00073   }
00074   memcpy(&outString[1], inString, len);
00075   outString[0] = len;
00076 }
00077 
00078 /* Define Class IDs */
00079 
00080 nsInternetConfigService::nsInternetConfigService()
00081 {
00082 }
00083 
00084 nsInternetConfigService::~nsInternetConfigService()
00085 {
00086 }
00087 
00088 
00089 /*
00090  * Implement the nsISupports methods...
00091  */
00092 NS_IMPL_ISUPPORTS1(nsInternetConfigService, nsIInternetConfigService)
00093 
00094 // void LaunchURL (in string url);
00095 // Given a url string, call ICLaunchURL using url
00096 // Under OS X use LaunchServices instead of IC
00097 NS_IMETHODIMP nsInternetConfigService::LaunchURL(const char *url)
00098 {
00099   nsresult rv = NS_ERROR_FAILURE; 
00100 
00101   CFURLRef myURLRef = ::CFURLCreateWithBytes(
00102                                              kCFAllocatorDefault,
00103                                              (const UInt8*)url,
00104                                              strlen(url),
00105                                              kCFStringEncodingUTF8, NULL);
00106   if (myURLRef)
00107   {
00108     rv = ::LSOpenCFURLRef(myURLRef, NULL);
00109     ::CFRelease(myURLRef);
00110   }
00111 
00112   return rv;
00113 }
00114 
00115 // boolean HasMappingForMIMEType (in string mimetype);
00116 // given a mime type, search Internet Config database for a mapping for that mime type
00117 NS_IMETHODIMP nsInternetConfigService::HasMappingForMIMEType(const char *mimetype, PRBool *_retval)
00118 {
00119   ICMapEntry entry;
00120   nsresult rv = GetMappingForMIMEType(mimetype, nsnull, &entry);
00121   if (rv == noErr)
00122     *_retval = PR_TRUE;
00123   else
00124     *_retval = PR_FALSE;
00125   return rv;
00126 }
00127 
00128 /* boolean hasProtocalHandler (in string protocol); */
00129 // returns NS_ERROR_NOT_AVAILABLE if the current application is registered for as the
00130 // protocol handler for protocol
00131 NS_IMETHODIMP nsInternetConfigService::HasProtocolHandler(const char *protocol, PRBool *_retval)
00132 {
00133   *_retval = PR_FALSE;            // Presume failure
00134   nsresult rv = NS_ERROR_FAILURE; // Ditto
00135 
00136   // Since protocol comes in with _just_ the protocol we have to add a ':' to
00137   // the end of it or LaunchServices will be very unhappy with the CFURLRef
00138   // created from it (crashes trying to look up a handler for it with
00139   // LSGetApplicationForURL, at least under 10.2.1)
00140   nsCAutoString scheme(protocol);
00141   scheme += ":";
00142   CFURLRef myURLRef = ::CFURLCreateWithBytes(
00143                                               kCFAllocatorDefault,
00144                                               (const UInt8 *)scheme.get(),
00145                                               scheme.Length(),
00146                                               kCFStringEncodingUTF8, NULL);
00147   if (myURLRef)
00148   {
00149     FSRef appFSRef;
00150   
00151     if (::LSGetApplicationForURL(myURLRef, kLSRolesAll, &appFSRef, NULL) == noErr)
00152     { // Now see if the FSRef for the found app == the running app
00153       ProcessSerialNumber psn;
00154       if (::GetCurrentProcess(&psn) == noErr)
00155       {
00156         FSRef runningAppFSRef;
00157         if (::GetProcessBundleLocation(&psn, &runningAppFSRef) == noErr)
00158         {
00159           if (::FSCompareFSRefs(&appFSRef, &runningAppFSRef) == noErr)
00160           { // Oops, the current app is the handler which would cause infinite recursion
00161             rv = NS_ERROR_NOT_AVAILABLE;
00162           }
00163           else
00164           {
00165             *_retval = PR_TRUE;
00166             rv = NS_OK;
00167           }
00168         }
00169       }
00170     }
00171     ::CFRelease(myURLRef);
00172   }
00173 
00174   return rv;
00175 }
00176 
00177 // This method does the dirty work of traipsing through IC mappings database
00178 // looking for a mapping for mimetype
00179 nsresult nsInternetConfigService::GetMappingForMIMEType(const char *mimetype, const char *fileextension, ICMapEntry *entry)
00180 {
00181   ICInstance  inst = nsInternetConfig::GetInstance();
00182   OSStatus    err = noErr;
00183   ICAttr      attr;
00184   Handle      prefH;
00185   PRBool      domimecheck = PR_TRUE;
00186   PRBool      gotmatch = PR_FALSE;
00187   ICMapEntry  ent;
00188   
00189   // if mime type is "unknown" or "octet stream" *AND* we have a file extension,
00190   // then disable match on mime type
00191   if (((nsCRT::strcasecmp(mimetype, UNKNOWN_CONTENT_TYPE) == 0) ||
00192        (nsCRT::strcasecmp(mimetype, APPLICATION_OCTET_STREAM) == 0)) &&
00193        fileextension)
00194     domimecheck = PR_FALSE;
00195   
00196   entry->totalLength = 0;
00197   if (inst)
00198   {
00199     err = ::ICBegin(inst, icReadOnlyPerm);
00200     if (err == noErr)
00201     {
00202       prefH = ::NewHandle(2048); // picked 2048 out of thin air
00203       if (prefH)
00204       {
00205         err = ::ICFindPrefHandle(inst, kICMapping, &attr, prefH);
00206         if (err == noErr)
00207         {
00208           long count;
00209           err = ::ICCountMapEntries(inst, prefH, &count);
00210           if (err == noErr)
00211           {
00212             long pos;
00213             for (long i = 1; i <= count; ++i)
00214             {
00215               err = ::ICGetIndMapEntry(inst, prefH, i, &pos, &ent);
00216               if (err == noErr)
00217               {
00218                 // first, do mime type check
00219                 if (domimecheck)
00220                 {
00221                   nsCAutoString temp((char *)&ent.MIMEType[1], (int)ent.MIMEType[0]);
00222                   if (!temp.EqualsIgnoreCase(mimetype))
00223                   {
00224                     // we need to do mime check, and check failed
00225                     // nothing here to see, move along
00226                     continue;
00227                   }
00228                 }
00229                 if (fileextension)
00230                 {
00231                   // if fileextension was passed in, compare that also
00232                   if (ent.extension[0]) // check for non-empty pascal string
00233                   {
00234                     nsCAutoString temp((char *)&ent.extension[1], (int)ent.extension[0]);
00235                     if (temp.EqualsIgnoreCase(fileextension))
00236                     {
00237                       // mime type and file extension match, we're outta here
00238                       gotmatch = PR_TRUE;
00239                       // copy over ICMapEntry
00240                       *entry = ent;
00241                       break;
00242                     }
00243                   }
00244                 }
00245                 else if(domimecheck)
00246                 {
00247                   // at this point, we've got our match because
00248                   // domimecheck is true, the mime strings match, and fileextension isn't passed in
00249                   // bad thing is we'll stop on first match, but what can you do?
00250                   gotmatch = PR_TRUE;
00251                   // copy over ICMapEntry
00252                   *entry = ent;
00253                   break;
00254                 }
00255               }
00256             }
00257           }
00258         }
00259         ::DisposeHandle(prefH);
00260       }
00261       else
00262       {
00263         err = memFullErr;
00264       }
00265       err = ::ICEnd(inst);
00266       if (err == noErr && gotmatch == PR_FALSE)
00267       {
00268         err = fnfErr; // return SOME kind of error
00269       }
00270     }
00271   }
00272   
00273   if (err != noErr)
00274     return NS_ERROR_FAILURE;
00275   else
00276     return NS_OK;
00277 }
00278 
00279 nsresult nsInternetConfigService::FillMIMEInfoForICEntry(ICMapEntry& entry, nsIMIMEInfo ** mimeinfo)
00280 {
00281   // create a mime info object and we'll fill it in based on the values from IC mapping entry
00282   nsresult  rv = NS_OK;
00283   nsRefPtr<nsMIMEInfoMac> info (new nsMIMEInfoMac());
00284   if (info)
00285   {
00286     nsCAutoString mimetype ((char *)&entry.MIMEType[1], entry.MIMEType[0]);
00287     // check if entry.MIMEType is empty, if so, set mime type to APPLICATION_OCTET_STREAM
00288     if (entry.MIMEType[0])
00289       info->SetMIMEType(mimetype);
00290     else
00291     { // The IC mappings seem to not be very agressive about determining the mime type if
00292       // all we have is a type or creator code.  This is a bandaid approach for when we
00293       // get a file of type 'TEXT' with no mime type mapping so that we'll display the
00294       // file rather than trying to download it.
00295       if (entry.fileType == 'TEXT')
00296         info->SetMIMEType(NS_LITERAL_CSTRING(TEXT_PLAIN));
00297       else
00298         info->SetMIMEType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM));
00299     }
00300     
00301     // convert entry.extension which is a Str255 
00302     // don't forget to remove the '.' in front of the file extension....
00303     nsCAutoString temp((char *)&entry.extension[2], entry.extension[0] > 0 ? (int)entry.extension[0]-1 : 0);
00304     info->AppendExtension(temp);
00305     info->SetMacType(entry.fileType);
00306     info->SetMacCreator(entry.fileCreator);
00307     temp.Assign((char *) &entry.entryName[1], entry.entryName[0]);
00308     info->SetDescription(NS_ConvertASCIItoUCS2(temp));
00309     
00310     temp.Assign((char *) &entry.postAppName[1], entry.postAppName[0]);
00311     info->SetDefaultDescription(NS_ConvertASCIItoUCS2(temp));
00312     
00313     if (entry.flags & kICMapPostMask)
00314     {
00315       // there is a post processor app
00316       info->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
00317       nsCOMPtr<nsILocalFileMac> file (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00318       if (file)
00319       {
00320         rv = file->InitToAppWithCreatorCode(entry.postCreator);
00321         if (rv == NS_OK)
00322         {
00323           nsCOMPtr<nsIFile> nsfile = do_QueryInterface(file, &rv);
00324           if (rv == NS_OK)
00325             info->SetDefaultApplication(nsfile);
00326         }
00327       }
00328     }
00329     else
00330     {
00331       // there isn't a post processor app so set the preferred action to be save to disk.
00332       info->SetPreferredAction(nsIMIMEInfo::saveToDisk);
00333     }
00334     
00335     *mimeinfo = info;
00336     NS_IF_ADDREF(*mimeinfo);
00337   }
00338   else // we failed to allocate the info object...
00339     rv = NS_ERROR_FAILURE;
00340    
00341   return rv;
00342 }
00343 
00344 /* void FillInMIMEInfo (in string mimetype, in string fileExtension, out nsIMIMEInfo mimeinfo); */
00345 NS_IMETHODIMP nsInternetConfigService::FillInMIMEInfo(const char *mimetype, const char * aFileExtension, nsIMIMEInfo **mimeinfo)
00346 {
00347   nsresult    rv;
00348   ICMapEntry  entry;
00349   
00350   NS_ENSURE_ARG_POINTER(mimeinfo);
00351   *mimeinfo = nsnull;
00352 
00353   if (aFileExtension)
00354   {
00355     nsCAutoString fileExtension;
00356     fileExtension.Assign(".");  
00357     fileExtension.Append(aFileExtension);
00358     rv = GetMappingForMIMEType(mimetype, fileExtension.get(), &entry);
00359   }
00360   else
00361   {
00362     rv = GetMappingForMIMEType(mimetype, nsnull, &entry);
00363   }
00364   
00365   if (rv == NS_OK)
00366     rv = FillMIMEInfoForICEntry(entry, mimeinfo);
00367   else
00368     rv = NS_ERROR_FAILURE;
00369 
00370   return rv;
00371 }
00372 
00373 NS_IMETHODIMP nsInternetConfigService::GetMIMEInfoFromExtension(const char *aFileExt, nsIMIMEInfo **_retval)
00374 {
00375   nsresult    rv = NS_ERROR_FAILURE;
00376   ICInstance  instance = nsInternetConfig::GetInstance();
00377   if (instance)
00378   {
00379     nsCAutoString filename("foobar.");
00380     filename += aFileExt;
00381     Str255  pFileName;
00382     ConvertCharStringToStr255(filename.get(), pFileName);
00383     ICMapEntry  entry;
00384     OSStatus  err = ::ICMapFilename(instance, pFileName, &entry);
00385     if (err == noErr)
00386     {
00387       rv = FillMIMEInfoForICEntry(entry, _retval);
00388     }
00389   }   
00390   return rv;
00391 }
00392 
00393 
00394 NS_IMETHODIMP nsInternetConfigService::GetMIMEInfoFromTypeCreator(PRUint32 aType, PRUint32 aCreator, const char *aFileExt, nsIMIMEInfo **_retval)
00395 {
00396   nsresult    rv = NS_ERROR_FAILURE;
00397   ICInstance  instance = nsInternetConfig::GetInstance();
00398   if (instance)
00399   {
00400     nsCAutoString filename("foobar.");
00401     filename += aFileExt;
00402     Str255  pFileName;
00403     ConvertCharStringToStr255(filename.get(), pFileName);
00404     ICMapEntry  entry;
00405     OSStatus  err = ::ICMapTypeCreator(instance, aType, aCreator, pFileName, &entry);
00406     if (err == noErr)
00407       rv = FillMIMEInfoForICEntry(entry,_retval);
00408   }
00409   return rv;
00410 }
00411 
00412 
00413 NS_IMETHODIMP nsInternetConfigService::GetFileMappingFlags(FSSpec* fsspec, PRBool lookupByExtensionFirst, PRInt32 *_retval)
00414 {
00415   nsresult  rv = NS_ERROR_FAILURE;
00416   OSStatus  err = noErr;
00417 
00418   NS_ENSURE_ARG(_retval);
00419   *_retval = -1;
00420   
00421   ICInstance instance = nsInternetConfig::GetInstance();
00422   if (instance)
00423   {
00424     ICMapEntry  entry;
00425     
00426     if (lookupByExtensionFirst)
00427       err = ::ICMapFilename(instance, fsspec->name, &entry);
00428   
00429     if (!lookupByExtensionFirst || err != noErr)
00430     {
00431       FInfo info;
00432       err = FSpGetFInfo(fsspec, &info);
00433       if (err == noErr)
00434         err = ::ICMapTypeCreator(instance, info.fdType, info.fdCreator, fsspec->name, &entry);
00435     }
00436 
00437     if (err == noErr)
00438       *_retval = entry.flags;
00439      
00440      rv = NS_OK;
00441   }
00442   return rv;
00443 }
00444 
00445 
00446 /* void GetDownloadFolder (out FSSpec fsspec); */
00447 NS_IMETHODIMP nsInternetConfigService::GetDownloadFolder(FSSpec *fsspec)
00448 {
00449   ICInstance  inst = nsInternetConfig::GetInstance();
00450   OSStatus    err;
00451   Handle      prefH;
00452   nsresult    rv = NS_ERROR_FAILURE;
00453   
00454   NS_ENSURE_ARG_POINTER(fsspec);
00455   
00456   if (inst)
00457   {
00458     err = ::ICBegin(inst, icReadOnlyPerm);
00459     if (err == noErr)
00460     {
00461       prefH = ::NewHandle(256); // ICFileSpec ~= 112 bytes + variable, 256 bytes hopefully is sufficient
00462       if (prefH)
00463       {
00464         ICAttr  attr;
00465         err = ::ICFindPrefHandle(inst, kICDownloadFolder, &attr, prefH);
00466         if (err == noErr)
00467         {
00468           err = ::Munger(prefH, 0, NULL, kICFileSpecHeaderSize, (Ptr)-1, 0);
00469           if (err == noErr)
00470           {
00471             Boolean wasChanged;
00472             err = ::ResolveAlias(NULL, (AliasHandle)prefH, fsspec, &wasChanged);
00473             if (err == noErr)
00474             {
00475               rv = NS_OK;
00476             }
00477             else
00478             { // ResolveAlias for the DownloadFolder failed - try grabbing the FSSpec
00479               err = ::ICFindPrefHandle(inst, kICDownloadFolder, &attr, prefH);
00480               if (err == noErr)
00481               { // Use FSMakeFSSpec to verify the saved FSSpec is still valid
00482                 FSSpec  tempSpec = (*(ICFileSpecHandle)prefH)->fss;
00483                 err = ::FSMakeFSSpec(tempSpec.vRefNum, tempSpec.parID, tempSpec.name, fsspec);
00484                 if (err == noErr)
00485                   rv = NS_OK;
00486               }
00487             }
00488           }
00489         }
00490         // Best not to leave that handle laying around
00491         DisposeHandle(prefH);
00492       }
00493       err = ::ICEnd(inst);
00494     }
00495   }
00496   return rv;
00497 }
00498 
00499 nsresult nsInternetConfigService::GetICKeyPascalString(PRUint32 inIndex, const unsigned char*& outICKey)
00500 {
00501   nsresult  rv = NS_OK;
00502 
00503   switch (inIndex)
00504   {
00505     case eICColor_WebBackgroundColour: outICKey = kICWebBackgroundColour; break;
00506     case eICColor_WebReadColor:        outICKey = kICWebReadColor;        break;
00507     case eICColor_WebTextColor:        outICKey = kICWebTextColor;        break;
00508     case eICColor_WebUnreadColor:      outICKey = kICWebUnreadColor;      break;
00509 
00510     case eICBoolean_WebUnderlineLinks: outICKey = kICWebUnderlineLinks;  break;
00511     case eICBoolean_UseFTPProxy:       outICKey = kICUseFTPProxy;        break;
00512     case eICBoolean_UsePassiveFTP:     outICKey = kICUsePassiveFTP;      break;
00513     case eICBoolean_UseHTTPProxy:      outICKey = kICUseHTTPProxy;       break;
00514     case eICBoolean_NewMailDialog:     outICKey = kICNewMailDialog;      break;
00515     case eICBoolean_NewMailFlashIcon:  outICKey = kICNewMailFlashIcon;   break;
00516     case eICBoolean_NewMailPlaySound:  outICKey = kICNewMailPlaySound;   break;
00517     case eICBoolean_UseGopherProxy:    outICKey = kICUseGopherProxy;     break;
00518     case eICBoolean_UseSocks:          outICKey = kICUseSocks;           break;
00519 
00520     case eICString_WWWHomePage:        outICKey = kICWWWHomePage;        break;
00521     case eICString_WebSearchPagePrefs: outICKey = kICWebSearchPagePrefs; break;
00522     case eICString_MacSearchHost:      outICKey = kICMacSearchHost;      break;
00523     case eICString_FTPHost:            outICKey = kICFTPHost;            break;
00524     case eICString_FTPProxyUser:       outICKey = kICFTPProxyUser;       break;
00525     case eICString_FTPProxyAccount:    outICKey = kICFTPProxyAccount;    break;
00526     case eICString_FTPProxyHost:       outICKey = kICFTPProxyHost;       break;
00527     case eICString_FTPProxyPassword:   outICKey = kICFTPProxyPassword;   break;
00528     case eICString_HTTPProxyHost:      outICKey = kICHTTPProxyHost;      break;
00529     case eICString_LDAPSearchbase:     outICKey = kICLDAPSearchbase;     break;
00530     case eICString_LDAPServer:         outICKey = kICLDAPServer;         break;
00531     case eICString_SMTPHost:           outICKey = kICSMTPHost;           break;
00532     case eICString_Email:              outICKey = kICEmail;              break;
00533     case eICString_MailAccount:        outICKey = kICMailAccount;        break;
00534     case eICString_MailPassword:       outICKey = kICMailPassword;       break;
00535     case eICString_NewMailSoundName:   outICKey = kICNewMailSoundName;   break;
00536     case eICString_NNTPHost:           outICKey = kICNNTPHost;           break;
00537     case eICString_NewsAuthUsername:   outICKey = kICNewsAuthUsername;   break;
00538     case eICString_NewsAuthPassword:   outICKey = kICNewsAuthPassword;   break;
00539     case eICString_InfoMacPreferred:   outICKey = kICInfoMacPreferred;   break;
00540     case eICString_Organization:       outICKey = kICOrganization;       break;
00541     case eICString_QuotingString:      outICKey = kICQuotingString;      break;
00542     case eICString_RealName:           outICKey = kICRealName;           break;
00543     case eICString_FingerHost:         outICKey = kICFingerHost;         break;
00544     case eICString_GopherHost:         outICKey = kICGopherHost;         break;
00545     case eICString_GopherProxy:        outICKey = kICGopherProxy;        break;
00546     case eICString_SocksHost:          outICKey = kICSocksHost;          break;
00547     case eICString_TelnetHost:         outICKey = kICTelnetHost;         break;
00548     case eICString_IRCHost:            outICKey = kICIRCHost;            break;
00549     case eICString_UMichPreferred:     outICKey = kICUMichPreferred;     break;
00550     case eICString_WAISGateway:        outICKey = kICWAISGateway;        break;
00551     case eICString_WhoisHost:          outICKey = kICWhoisHost;          break;
00552     case eICString_PhHost:             outICKey = kICPhHost;             break;
00553     case eICString_NTPHost:            outICKey = kICNTPHost;            break;
00554     case eICString_ArchiePreferred:    outICKey = kICArchiePreferred;    break;
00555     
00556     case eICText_MailHeaders:          outICKey = kICMailHeaders;        break;
00557     case eICText_Signature:            outICKey = kICSignature;          break;
00558     case eICText_NewsHeaders:          outICKey = kICNewsHeaders;        break;
00559     case eICText_SnailMailAddress:     outICKey = kICSnailMailAddress;   break;
00560     case eICText_Plan:                 outICKey = kICPlan;               break;
00561 
00562     default:
00563       rv = NS_ERROR_INVALID_ARG;
00564   }
00565   return rv;
00566 }
00567 
00568 
00569 nsresult nsInternetConfigService::GetICPreference(PRUint32 inKey, 
00570                                                   void *outData, long *ioSize)
00571 {
00572   const unsigned char *icKey;
00573   nsresult  rv = GetICKeyPascalString(inKey, icKey);
00574   if (rv == NS_OK)
00575   {
00576     ICInstance  instance = nsInternetConfig::GetInstance();
00577     if (instance)
00578     {
00579       OSStatus  err;
00580       ICAttr    junk;
00581       err = ::ICGetPref(instance, icKey, &junk, outData, ioSize);
00582       if (err != noErr)
00583         rv = NS_ERROR_UNEXPECTED;
00584     }
00585     else
00586       rv = NS_ERROR_FAILURE;
00587   }
00588   return rv;
00589 }
00590 
00591 
00592 NS_IMETHODIMP nsInternetConfigService::GetString(PRUint32 inKey, nsACString& value)
00593 {
00594   long      size = 256;
00595   char      buffer[256];
00596   nsresult  rv = GetICPreference(inKey, (void *)&buffer, &size);
00597   if (rv == NS_OK)
00598   {
00599     if (size == 0)
00600     {
00601       value = "";
00602       rv = NS_ERROR_UNEXPECTED;
00603     }
00604     else
00605     { // Buffer is a Pascal string so adjust for length byte when assigning
00606       value.Assign(&buffer[1], (unsigned char)buffer[0]);
00607     }
00608   }
00609   return rv;
00610 }
00611 
00612 
00613 NS_IMETHODIMP nsInternetConfigService::GetColor(PRUint32 inKey, PRUint32 *outColor)
00614 {
00615 // We're 'borrowing' this macro from nscolor.h so that uriloader doesn't depend on gfx.
00616 // Make a color out of r,g,b values. This assumes that the r,g,b values are
00617 // properly constrained to 0-255. This also assumes that a is 255.
00618 
00619   #define MAKE_NS_RGB(_r,_g,_b) \
00620     ((PRUint32) ((255 << 24) | ((_b)<<16) | ((_g)<<8) | (_r)))
00621 
00622   RGBColor  buffer;
00623   long      size = sizeof(RGBColor);
00624   nsresult  rv = GetICPreference(inKey, &buffer, &size);
00625   if (rv == NS_OK)
00626   {
00627     if (size != sizeof(RGBColor))
00628     { // default to white if we didn't get the right size
00629       *outColor = MAKE_NS_RGB(0xff, 0xff, 0xff);
00630     }
00631     else
00632     { // convert to a web color
00633       *outColor = MAKE_NS_RGB(buffer.red >> 8, buffer.green >> 8, buffer.blue >> 8);
00634     }
00635   }
00636   return rv;
00637 }
00638 
00639 
00640 NS_IMETHODIMP nsInternetConfigService::GetBoolean(PRUint32 inKey, PRBool *outFlag)
00641 {
00642   Boolean   buffer;
00643   long      size = sizeof(Boolean);
00644   nsresult  rv = GetICPreference(inKey, (void *)&buffer, &size);
00645   if (rv == NS_OK)
00646   {
00647     if ((size_t)size < sizeof(Boolean))
00648       *outFlag = PR_FALSE;  // default to false if we didn't get the right amount of data
00649     else
00650       *outFlag = buffer;
00651   }
00652   return rv;
00653 }