diff --git a/mozilla/xpfe/components/winhooks/makefile.win b/mozilla/xpfe/components/winhooks/makefile.win new file mode 100644 index 00000000000..b323438b800 --- /dev/null +++ b/mozilla/xpfe/components/winhooks/makefile.win @@ -0,0 +1,60 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/NPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Bill Law + +MODULE=winhooks + +DEPTH=..\..\.. + +XPIDL_MODULE=winhooks + +XPIDLSRCS=\ + .\nsIWindowsHooks.idl \ + $(NULL) + +include <$(DEPTH)/config/config.mak> + +DLLNAME = winhooks +DLL1NAME = winhooks +PDBFILE = $(DLLNAME).pdb +MAPFILE = $(DLLNAME).map +DLL =.\$(OBJDIR)\$(DLLNAME).dll +MAKE_OBJ_TYPE = DLL + +LINCS = \ + $(NULL) + +LLIBS = \ + $(DIST)\lib\xpcom.lib \ + $(NULL) + +OBJS = \ + .\$(OBJDIR)\nsWindowsHooks.obj \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +install:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin\components + +clobber:: + rm -f $(DIST)\bin\components\$(DLLNAME).dll + diff --git a/mozilla/xpfe/components/winhooks/nsIWindowsHooks.idl b/mozilla/xpfe/components/winhooks/nsIWindowsHooks.idl new file mode 100644 index 00000000000..d3a8b133b48 --- /dev/null +++ b/mozilla/xpfe/components/winhooks/nsIWindowsHooks.idl @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Bill Law + */ + +#include "nsISupports.idl" + + +/* These interface provides support for integrating Mozilla into Windows. + * This integration consists primarily of setting Mozilla as the "default + * browser." Or more precisely, setting Mozilla as the executable to + * handle certain file types. + * + * There are two subtly different types of desktop objects that Mozilla + * can be configured to "handle:" + * o File types (based on file extension) + * o Internet shortcuts (based on URL protocol). + * + * While these are different types of objects, the mechanism by which + * applications are matched with them is essentially the same. + * + * In the case of files, there is one more level of indirection. File + * extensions are assigned a "file type" via a Windows registry entry. + * For example, given the file extension ".foo", the file type is + * determined by examing the value stored in the "default" value stored + * at the registry key HEKY_LOCAL_MACHINE\Software\Classes\.foo. + * + * Once you have the "file type" then you use that the same way you use + * Internet Shortcut protocol names to determine which application to + * launch. The application is specified by the default value stored in + * the registry key + * HKEY_LOCAL_MACHINE\Software\Classes\\shell\open\command, where + * is the "file type" or protocol name. + * + * If there are additional keys under "shell" then these appear on the + * context menu for files/shortcuts of this type. Typically, there are + * entries for "print." But Mozilla does not currently support a command + * line option to print so we don't offer that. + * + * Previously, Netscape Communicator made itself the handler of standard + * web things by creating a new file type "NetscapeMarkup" and mapping + * extensions to that (.htm, .html, .shtml, .xbm), or, by setting itself + * up as the "handler" for the file types of other web things (.jpg, .gif) + * and Internet Shortcut protocols (ftp, gopher, http, https, mailto, news, + * snews). + * + * In order to better enable Mozilla to co-exist with other browsers + * (including Communicator), it will create yet another new file type, + * "MozillaMarkup," that will be used to make Mozilla the default handler + * for certain file extensions. This will be done by remapping those + * extensions to this new type. + * + * Mozilla will attempt to remember the original mapping and restore it + * when the user decides to no longer have Mozilla be the default handler + * for that extension. + * + * Mozilla will drop support for some items that are no longer germane: + * the .shtml file extension and the gopher: protocol. We will also, perhaps + * only temporarily, drop support for protocols that aren't accessible from + * the command line: mailto:, news:, and snews:. + * + * We will be adding support for the chrome: protocol (using the "-chrome" + * command line option) and for .png, .xul and .xml file extensions. + * + * Missing Features: + * + * Currently, there is no way to extend the set of file types or protocols + * that Mozilla can be associated with (save manually tweaking the Windows + * registry). This is likely to be a problem for branded Mozilla browsers + * that might support specialized file types or protocols (e.g., .aim files). + * + * The plan is to extend this interface so that such file types and protocols + * can be set up using the implementation of the interfaces defined here. + */ + +/* nsIWindowsHooksSettings + * + * This interface is used to get/set the user preferences relating to + * "windows hooks" (aka "windows integration"). It is basically just + * a conglomeration of a bunch of boolean attributes; it exists mainly + * for historical reasons (it corresponds to the internal Prefs struct + * that was in nsIDefaultBrowser.h in Mozilla Classic). + */ +[scriptable, uuid(4ce9aa90-0a6a-11d4-8076-00600811a9c3)] +interface nsIWindowsHooksSettings : nsISupports { + + // Internet shortcuts (based on "protocol"). + attribute boolean isHandlingHTTP; + attribute boolean isHandlingHTTPS; + attribute boolean isHandlingFTP; + attribute boolean isHandlingCHROME; + + // File handling (based on extension). + attribute boolean isHandlingHTML; + attribute boolean isHandlingJPEG; + attribute boolean isHandlingGIF; + attribute boolean isHandlingPNG; + attribute boolean isHandlingXML; + attribute boolean isHandlingXUL; + +}; + +/* nsIWindowsHooks + * + * This interface describes the service that you can use to + * get/set the various windows integration features specified + * by the nsIWindowsHooksPrefs attributes. + */ +[scriptable, uuid(19c9fbb0-06a3-11d4-8076-00600811a9c3)] +interface nsIWindowsHooks : nsISupports { + + // Settings. Get/set this to query or modify them. The Windows + // registry is updated when you set this attribute. + attribute nsIWindowsHooksSettings settings; + +}; + +%{C++ +#define NS_IWINDOWSHOOKS_PROGID "component://mozilla/winhooks" +#define NS_IWINDOWSHOOKS_CLASSNAME "Mozilla Windows Integration Hooks" +%} diff --git a/mozilla/xpfe/components/winhooks/nsWindowsHooks.cpp b/mozilla/xpfe/components/winhooks/nsWindowsHooks.cpp new file mode 100644 index 00000000000..00bee52ba6a --- /dev/null +++ b/mozilla/xpfe/components/winhooks/nsWindowsHooks.cpp @@ -0,0 +1,382 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Bill Law + */ +#include "nsIWindowsHooks.h" +#include "nsIGenericFactory.h" + +#include + +// Implementation utilities. +#include "nsWindowsHooksUtil.cpp" + +// Objects that describe the Windows registry entries that we need to tweak. +static ProtocolRegistryEntry + http( "http" ), + https( "https" ), + ftp( "ftp" ), + chrome( "chrome" ); + +const char *jpgExts[] = { ".jpg", ".jpeg", 0 }; +const char *gifExts[] = { ".gif", 0 }; +const char *pngExts[] = { ".png", 0 }; +const char *xmlExts[] = { ".xml", 0 }; +const char *xulExts[] = { ".xul", 0 }; +const char *htmExts[] = { ".htm", ".html", 0 }; + +static FileTypeRegistryEntry + jpg( jpgExts, "MozillaJPEG", "Mozilla JPEG Image File" ), + gif( gifExts, "MozillaGIF", "Mozilla GIF Image File" ), + png( pngExts, "MozillaPNG", "Mozilla Portable Network Graphic Image File" ), + xml( xmlExts, "MozillaXML", "Mozilla Extensible Markup Language Document" ), + xul( xulExts, "MozillaXUL", "Mozilla Extensible User-interface Language Document" ); + +static EditableFileTypeRegistryEntry + mozillaMarkup( htmExts, "MozillaHTML", "Mozilla Hypertext Markup Language Document" ); + + +/* c09bc130-0a71-11d4-8076-00600811a9c3 */ +#define NS_IWINDOWSHOOKS_CID \ + { 0xc09bc130, 0x0a71, 0x11d4, {0x80, 0x76, 0x00, 0x60, 0x08, 0x11, 0xa9, 0xc3} } + +// Implementation of the nsIWindowsHooksSettings interface. +class nsWindowsHooksSettings : public nsIWindowsHooksSettings { +public: + // ctor/dtor + nsWindowsHooksSettings(); + virtual ~nsWindowsHooksSettings(); + + // Declare all interface methods we must implement. + NS_DECL_ISUPPORTS + NS_DECL_NSIWINDOWSHOOKSSETTINGS + + // Typedef for nsIWindowsHooksSettings getter/setter member functions. + typedef nsresult (__stdcall nsIWindowsHooksSettings::*getter)( PRBool* ); + typedef nsresult (__stdcall nsIWindowsHooksSettings::*setter)( PRBool ); + +protected: + // General purpose getter. + NS_IMETHOD Get( PRBool *result, PRBool nsWindowsHooksSettings::*member ); + // General purpose setter. + NS_IMETHOD Set( PRBool value, PRBool nsWindowsHooksSettings::*member ); + +private: + // Internet shortcut protocols. + struct { + PRBool mHandleHTTP; + PRBool mHandleHTTPS; + PRBool mHandleFTP; + PRBool mHandleCHROME; + }; + // File types. + struct { + PRBool mHandleHTML; + PRBool mHandleJPEG; + PRBool mHandleGIF; + PRBool mHandlePNG; + PRBool mHandleXML; + PRBool mHandleXUL; + }; + friend class nsWindowsHooks; +}; // nsWindowsHooksSettings + +// Use standard implementation of nsISupports stuff. +NS_IMPL_ISUPPORTS1( nsWindowsHooksSettings, nsIWindowsHooksSettings ); + +nsWindowsHooksSettings::nsWindowsHooksSettings() { + NS_INIT_ISUPPORTS(); +} + +nsWindowsHooksSettings::~nsWindowsHooksSettings() { +} + +// Generic getter. +NS_IMETHODIMP +nsWindowsHooksSettings::Get( PRBool *result, PRBool nsWindowsHooksSettings::*member ) { + NS_ENSURE_ARG( result ); + NS_ENSURE_ARG( member ); + *result = this->*member; + return NS_OK; +} + +// Generic setter. +NS_IMETHODIMP +nsWindowsHooksSettings::Set( PRBool value, PRBool nsWindowsHooksSettings::*member ) { + NS_ENSURE_ARG( member ); + this->*member = value; + return NS_OK; +} + +// Macros to define specific getter/setter methods. +#define DEFINE_GETTER_AND_SETTER( attr, member ) \ +NS_IMETHODIMP \ +nsWindowsHooksSettings::Get##attr ( PRBool *result ) { \ + return this->Get( result, &nsWindowsHooksSettings::member ); \ +} \ +NS_IMETHODIMP \ +nsWindowsHooksSettings::Set##attr ( PRBool value ) { \ + return this->Set( value, &nsWindowsHooksSettings::member ); \ +} + +// Define all the getter/setter methods: +DEFINE_GETTER_AND_SETTER( IsHandlingHTML, mHandleHTML ) +DEFINE_GETTER_AND_SETTER( IsHandlingJPEG, mHandleJPEG ) +DEFINE_GETTER_AND_SETTER( IsHandlingGIF, mHandleGIF ) +DEFINE_GETTER_AND_SETTER( IsHandlingPNG, mHandlePNG ) +DEFINE_GETTER_AND_SETTER( IsHandlingXML, mHandleXML ) +DEFINE_GETTER_AND_SETTER( IsHandlingXUL, mHandleXUL ) +DEFINE_GETTER_AND_SETTER( IsHandlingHTTP, mHandleHTTP ) +DEFINE_GETTER_AND_SETTER( IsHandlingHTTPS, mHandleHTTPS ) +DEFINE_GETTER_AND_SETTER( IsHandlingFTP, mHandleFTP ) +DEFINE_GETTER_AND_SETTER( IsHandlingCHROME, mHandleCHROME ) + + +// Implementation of the nsIWindowsHooks interface. +class nsWindowsHooks : public nsIWindowsHooks { +public: + // ctor/dtor + nsWindowsHooks(); + virtual ~nsWindowsHooks(); + + // Declare all interface methods we must implement. + NS_DECL_ISUPPORTS + NS_DECL_NSIWINDOWSHOOKS + +protected: + // Internal flavor of GetPreferences. + NS_IMETHOD GetSettings( nsWindowsHooksSettings ** ); + + // Set registry according to settings. + NS_IMETHOD SetRegistry(); + +private: + // Module stuff. + static NS_METHOD CreateWindowsHooks( nsISupports *aOuter, + REFNSIID aIID, + void **aResult ); + static nsWindowsHooks *mInstance; + +public: + static nsModuleComponentInfo components[]; +}; // nsWindowsHooksSettings + +// Use standard implementation of nsISupports stuff. +NS_IMPL_ISUPPORTS1( nsWindowsHooks, nsIWindowsHooks ); + +nsWindowsHooks::nsWindowsHooks() { + NS_INIT_ISUPPORTS(); +} + +nsWindowsHooks::~nsWindowsHooks() { +} + +// Internal GetPreferences. +NS_IMETHODIMP +nsWindowsHooks::GetSettings( nsWindowsHooksSettings **result ) { + nsresult rv = NS_OK; + + // Validate input arg. + NS_ENSURE_ARG( result ); + + // Allocate prefs object. + nsWindowsHooksSettings *prefs = *result = new nsWindowsHooksSettings; + NS_ENSURE_TRUE( prefs, NS_ERROR_OUT_OF_MEMORY ); + + // Got it, increment ref count. + NS_ADDREF( prefs ); + + // Get each registry value and copy to prefs structure. + prefs->mHandleHTTP = (void*)( BoolRegistryEntry( "isHandlingHTTP" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleHTTPS = (void*)( BoolRegistryEntry( "isHandlingHTTPS" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleFTP = (void*)( BoolRegistryEntry( "isHandlingFTP" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleCHROME = (void*)( BoolRegistryEntry( "isHandlingCHROME" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleHTML = (void*)( BoolRegistryEntry( "isHandlingHTML" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleJPEG = (void*)( BoolRegistryEntry( "isHandlingJPEG" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleGIF = (void*)( BoolRegistryEntry( "isHandlingGIF" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandlePNG = (void*)( BoolRegistryEntry( "isHandlingPNG" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleXML = (void*)( BoolRegistryEntry( "isHandlingXML" ) ) ? PR_TRUE : PR_FALSE; + prefs->mHandleXUL = (void*)( BoolRegistryEntry( "isHandlingXUL" ) ) ? PR_TRUE : PR_FALSE; + +#ifdef DEBUG_law +NS_WARN_IF_FALSE( NS_SUCCEEDED( rv ), "GetPreferences failed" ); +#endif + + return rv; +} + +// Public interface uses internal plus a QI to get to the proper result. +NS_IMETHODIMP +nsWindowsHooks::GetSettings( nsIWindowsHooksSettings **_retval ) { + // Allocate prefs object. + nsWindowsHooksSettings *prefs; + nsresult rv = this->GetSettings( &prefs ); + + if ( NS_SUCCEEDED( rv ) ) { + // QI to proper interface. + rv = prefs->QueryInterface( NS_GET_IID( nsIWindowsHooksSettings ), (void**)_retval ); + // Release (to undo our Get...). + NS_RELEASE( prefs ); + } + + return rv; +} + +// Utility to set PRBool registry value from getter method. +nsresult putPRBoolIntoRegistry( const char* valueName, + nsIWindowsHooksSettings *prefs, + nsWindowsHooksSettings::getter memFun ) { + // Use getter method to extract attribute from prefs. + PRBool boolValue; + (void)(prefs->*memFun)( &boolValue ); + // Convert to DWORD. + DWORD dwordValue = boolValue; + // Store into registry. + BoolRegistryEntry pref( valueName ); + nsresult rv = boolValue ? pref.set() : pref.reset(); + + return rv; +} + +/* void setPreferences (in nsIWindowsHooksSettings prefs); */ +NS_IMETHODIMP +nsWindowsHooks::SetSettings(nsIWindowsHooksSettings *prefs) { + nsresult rv = NS_ERROR_FAILURE; + + putPRBoolIntoRegistry( "isHandlingHTTP", prefs, &nsIWindowsHooksSettings::GetIsHandlingHTTP ); + putPRBoolIntoRegistry( "isHandlingHTTPS", prefs, &nsIWindowsHooksSettings::GetIsHandlingHTTPS ); + putPRBoolIntoRegistry( "isHandlingFTP", prefs, &nsIWindowsHooksSettings::GetIsHandlingFTP ); + putPRBoolIntoRegistry( "isHandlingCHROME", prefs, &nsIWindowsHooksSettings::GetIsHandlingCHROME ); + putPRBoolIntoRegistry( "isHandlingHTML", prefs, &nsIWindowsHooksSettings::GetIsHandlingHTML ); + putPRBoolIntoRegistry( "isHandlingJPEG", prefs, &nsIWindowsHooksSettings::GetIsHandlingJPEG ); + putPRBoolIntoRegistry( "isHandlingGIF", prefs, &nsIWindowsHooksSettings::GetIsHandlingGIF ); + putPRBoolIntoRegistry( "isHandlingPNG", prefs, &nsIWindowsHooksSettings::GetIsHandlingPNG ); + putPRBoolIntoRegistry( "isHandlingXML", prefs, &nsIWindowsHooksSettings::GetIsHandlingXML ); + putPRBoolIntoRegistry( "isHandlingXUL", prefs, &nsIWindowsHooksSettings::GetIsHandlingXUL ); + + rv = SetRegistry(); + + return rv; +} + +// Get preferences and start handling everything selected. +NS_IMETHODIMP +nsWindowsHooks::SetRegistry() { + nsresult rv = NS_OK; + + // Get raw prefs object. + nsWindowsHooksSettings *prefs; + rv = this->GetSettings( &prefs ); + + NS_ENSURE_TRUE( NS_SUCCEEDED( rv ), rv ); + + if ( prefs->mHandleHTML ) { + (void) mozillaMarkup.set(); + } else { + (void) mozillaMarkup.reset(); + } + if ( prefs->mHandleJPEG ) { + (void) jpg.set(); + } else { + (void) jpg.reset(); + } + if ( prefs->mHandleGIF ) { + (void) gif.set(); + } else { + (void) gif.reset(); + } + if ( prefs->mHandlePNG ) { + (void) png.set(); + } else { + (void) png.reset(); + } + if ( prefs->mHandleXML ) { + (void) xml.set(); + } else { + (void) xml.reset(); + } + if ( prefs->mHandleXUL ) { + (void) xul.set(); + } else { + (void) xul.reset(); + } + if ( prefs->mHandleHTTP ) { + (void) http.set(); + } else { + (void) http.reset(); + } + if ( prefs->mHandleHTTPS ) { + (void) https.set(); + } else { + (void) https.reset(); + } + if ( prefs->mHandleFTP ) { + (void) ftp.set(); + } else { + (void) ftp.reset(); + } + if ( prefs->mHandleCHROME ) { + (void) ftp.set(); + } else { + (void) ftp.reset(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsWindowsHooks::CreateWindowsHooks( nsISupports *aOuter, + REFNSIID aIID, + void **aResult ) { + if ( !aResult ) { + return NS_ERROR_INVALID_POINTER; + } + + if ( aOuter ) { + *aResult = nsnull; + return NS_ERROR_NO_AGGREGATION; + } + + if (mInstance == nsnull) { + mInstance = new nsWindowsHooks(); + } + + if ( mInstance == nsnull ) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = mInstance->QueryInterface( aIID, aResult ); + if ( NS_FAILED(rv) ) { + *aResult = nsnull; + } + + return rv; +} + +nsWindowsHooks* nsWindowsHooks::mInstance = nsnull; + +nsModuleComponentInfo nsWindowsHooks::components[] = { + { NS_IWINDOWSHOOKS_CLASSNAME, + NS_IWINDOWSHOOKS_CID, + NS_IWINDOWSHOOKS_PROGID, + nsWindowsHooks::CreateWindowsHooks }, +}; + +NS_IMPL_NSGETMODULE( "nsWindowsHooks", nsWindowsHooks::components ) + diff --git a/mozilla/xpfe/components/winhooks/nsWindowsHooksUtil.cpp b/mozilla/xpfe/components/winhooks/nsWindowsHooksUtil.cpp new file mode 100644 index 00000000000..91d912965a0 --- /dev/null +++ b/mozilla/xpfe/components/winhooks/nsWindowsHooksUtil.cpp @@ -0,0 +1,442 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Bill Law + */ +#include +#include +#include "nsString.h" + +// Where Mozilla stores its own registry values. +const char * const mozillaKeyName = "Software\\Mozilla\\Desktop"; + +static const char shortcutSuffix[] = " -url \"%1\""; +static const char chromeSuffix[] = " -chrome \"%1\""; + +// Returns the (fully-qualified) name of this executable. +static nsCString thisApplication() { + static nsCString result; + + if ( result.IsEmpty() ) { + char buffer[MAX_PATH] = { 0 }; + DWORD len = ::GetModuleFileName( NULL, buffer, sizeof buffer ); + len = ::GetShortPathName( buffer, buffer, sizeof buffer ); + + result = buffer; + result.ToUpperCase(); + } + + return result; +} + +// Returns this + +// RegistryEntry +// +// Generic registry entry (no saving of previous values). Each is comprised of: +// o A base HKEY +// o A subkey name. +// o An optional value name (empty for the "default" value). +// o The registry setting we'd like this entry to have when set. +struct RegistryEntry { + HKEY baseKey; // e.g., HKEY_CURRENT_USER + nsCString keyName; // Key name. + nsCString valueName; // Value name (can be empty, which implies NULL). + nsCString setting; // What we set it to. + + RegistryEntry( HKEY baseKey, const char* keyName, const char* valueName, const char* setting ) + : baseKey( baseKey ), keyName( keyName ), valueName( valueName ), setting( setting ) { + } + + PRBool isAlreadySet() const; + nsresult set(); + nsresult reset(); + nsCString currentSetting() const; + + // Return value name in proper form for passing to ::Reg functions + // (i.e., emptry string is converted to a NULL pointer). + const char* valueNameArg() const { + return valueName.IsEmpty() ? NULL : valueName.GetBuffer(); + } + + nsCString fullName() const; +}; + +// BoolRegistryEntry +// +// These are used to store the "windows integration" preferences. +// You can query the value via operator void* (i.e., if ( boolPref )... ). +// These are stored under HKEY_LOCAL_MACHINE\Software\Mozilla\Desktop. +// Set sets the stored value to "1". Reset deletes it (which implies 0). +struct BoolRegistryEntry : public RegistryEntry { + BoolRegistryEntry( const char *name ) + : RegistryEntry( HKEY_LOCAL_MACHINE, mozillaKeyName, name, "1" ) { + } + operator void*(); +}; + +// SavedRegistryEntry +// +// Like a plain RegistryEntry, but set/reset save/restore the +// it had before we set it. +struct SavedRegistryEntry : public RegistryEntry { + SavedRegistryEntry( HKEY baseKey, const char *keyName, const char *valueName, const char *setting ) + : RegistryEntry( baseKey, keyName, valueName, setting ) { + } + nsresult set(); + nsresult reset(); +}; + +// ProtocolRegistryEntry +// +// For setting entries for a given Internet Shortcut protocol. +// The key name is calculated as +// HKEY_LOCAL_MACHINE\Software\Classes\protocol\shell\open\command. +// The setting is this executable (with appropriate suffix). +// Set/reset are trickier in this case. +struct ProtocolRegistryEntry : public SavedRegistryEntry { + nsCString protocol; + ProtocolRegistryEntry( const char* protocol ) + : SavedRegistryEntry( HKEY_LOCAL_MACHINE, "", "", thisApplication() ), + protocol( protocol ) { + keyName = "Software\\Classes\\"; + keyName += protocol; + keyName += "\\shell\\open\\command"; + + // Append appropriate suffix to setting. + if ( protocol == "chrome" ) { + // Use "-chrome" command line flag. + setting += chromeSuffix; + } else { + // Use standard "-url" command line flag. + setting += shortcutSuffix; + } + } + nsresult set(); + nsresult reset(); +}; + +// DDERegistryEntry +// +// Like a protocol registry entry, but for the shell\open\ddeexec subkey. +// We don't need to do anything special for set/reset, either. +struct DDERegistryEntry : public SavedRegistryEntry { + DDERegistryEntry( const char *protocol ) + : SavedRegistryEntry( HKEY_LOCAL_MACHINE, "", "", thisApplication() ) { + keyName = "Software\\Classes\\"; + keyName += protocol; + keyName += "\\shell\\open\\ddeexec"; + } +}; + +// FileTypeRegistryEntry +// +// For setting entries relating to a file extension (or extensions). +// This object itself is for the "file type" associated with the extension. +// Set/reset manage the mapping from extension to the file type, as well. +struct FileTypeRegistryEntry : public ProtocolRegistryEntry { + nsCString fileType; + const char **ext; + nsCString desc; + FileTypeRegistryEntry ( const char **ext, const char *fileType, const char *desc ) + : ProtocolRegistryEntry( fileType ), + fileType( fileType ), + ext( ext ), + desc( desc ) { + } + nsresult set(); + nsresult reset(); +}; + +// EditableFileTypeRegistryEntry +// +// Extends FileTypeRegistryEntry by setting an additional handler for an "edit" command. +struct EditableFileTypeRegistryEntry : public FileTypeRegistryEntry { + EditableFileTypeRegistryEntry( const char **ext, const char *fileType, const char *desc ) + : FileTypeRegistryEntry( ext, fileType, desc ) { + } + nsresult set(); +}; + +// Generate the "full" name of this registry entry. +nsCString RegistryEntry::fullName() const { + nsCString result; + if ( baseKey == HKEY_CURRENT_USER ) { + result = "HKEY_CURRENT_USER\\"; + } else if ( baseKey == HKEY_LOCAL_MACHINE ) { + result = "HKEY_LOCAL_MACHINE\\"; + } else { + result = "\\"; + } + result += keyName; + if ( !valueName.IsEmpty() ) { + result += "["; + result += valueName; + result += "]"; + } + return result; +} + +// Tests whether registry entry already has desired setting. +PRBool RegistryEntry::isAlreadySet() const { + PRBool result = FALSE; + + nsCString current = currentSetting(); + + result = ( current == setting ); + + return result; +} + +// Gives registry entry the desired setting. +nsresult RegistryEntry::set() { +#ifdef DEBUG_law +printf( "Setting %s=%s\n", (const char*)fullName(), (const char*)setting ); +#endif + nsresult result = NS_ERROR_FAILURE; + + HKEY key; + LONG rc = ::RegOpenKey( baseKey, keyName, &key ); + + // See if key doesn't exist yet... + if ( rc == ERROR_FILE_NOT_FOUND ) { + rc = ::RegCreateKey( baseKey, keyName, &key ); + } + if ( rc == ERROR_SUCCESS ) { + char buffer[4096] = { 0 }; + DWORD len = sizeof buffer; + rc = ::RegQueryValueEx( key, valueNameArg(), NULL, NULL, (LPBYTE)buffer, &len ); + if ( strcmp( setting, buffer ) != 0 ) { + rc = ::RegSetValueEx( key, valueNameArg(), NULL, REG_SZ, (LPBYTE)(const char*)setting, strlen(setting) ); +#ifdef DEBUG_law +NS_WARN_IF_FALSE( rc == ERROR_SUCCESS, (const char*)fullName() ); +#endif + if ( rc == ERROR_SUCCESS ) { + result = NS_OK; + } + } else { + // Already has desired setting. + result = NS_OK; + } + ::RegCloseKey( key ); + } else { +#ifdef DEBUG_law +NS_WARN_IF_FALSE( rc == ERROR_SUCCESS, (const char*)fullName() ); +#endif + } + return result; +} + +// Get current setting, set new one, then save the previous. +nsresult SavedRegistryEntry::set() { + nsresult rv = NS_OK; + nsCString prev = currentSetting(); + // See if value is changing. + if ( setting != prev ) { + // Set new. + rv = RegistryEntry::set(); + if ( NS_SUCCEEDED( rv ) ) { + // Save old. + RegistryEntry( HKEY_LOCAL_MACHINE, "Software\\Mozilla\\Desktop", fullName(), prev ).set(); + } + } + return rv; +} + +// Set this entry and its corresponding DDE entry. The DDE entry +// must be turned off to stop Windows from trying to use DDE. +nsresult ProtocolRegistryEntry::set() { + // Set this entry. + nsresult rv = SavedRegistryEntry::set(); + + // Save and set corresponding DDE entry. This stops Windows from trying to use + // DDE (and getting an error). + nsCString ddeName = "Software\\Classes\\"; + ddeName += protocol; + ddeName += "\\shell\\open\\ddeexec"; + SavedRegistryEntry( HKEY_LOCAL_MACHINE, ddeName, NULL, NULL ).set(); + + // Special case. + if ( protocol = "http" ) { + // We need to zap HKR\Software\Classes\http\shell\open\ddeexec\Application + // because Communicator looks there to determine whether they're the + // "default browser." If they are (the value there is "NSShell" or "Netscape") + // then it will reset lots of registry entries, "stealing" them from us. + SavedRegistryEntry special( HKEY_LOCAL_MACHINE, "Software\\Classes\\http\\shell\\open\\ddeexec\\Application", NULL, NULL ); + nsCString specialVal = special.currentSetting(); + if ( specialVal == "NSShell" || specialVal == "Netscape" ) { + // Reset this so Communicator will at least prompt the user. + special.set(); + } + } + + return rv; +} + +// Not being a "saved" entry, we can't restore, so just delete it. +nsresult RegistryEntry::reset() { + HKEY key; + LONG rc = ::RegOpenKey( baseKey, keyName, &key ); + if ( rc == ERROR_SUCCESS ) { + rc = ::RegDeleteValue( key, valueNameArg() ); + } + return NS_OK; +} + +// Resets registry entry to the saved value (if there is one). We first +// ensure that we still "own" that entry (by comparing its value to what +// we would set it to). +nsresult SavedRegistryEntry::reset() { + nsresult result = NS_OK; + + // Get current setting for this key/value. + nsCString current = currentSetting(); + + // Test if we "own" it. + if ( current == setting ) { + // Unset it, then. First get saved value it had previously. + RegistryEntry saved = RegistryEntry( HKEY_LOCAL_MACHINE, mozillaKeyName, fullName(), "" ); + saved.setting = saved.currentSetting(); + if ( !saved.setting.IsEmpty() ) { + // Set to previous value. + setting = saved.setting; + result = RegistryEntry::set(); + // Remove saved entry. + saved.reset(); + } else { + // Just delete this key/value. + result = RegistryEntry::reset(); + } + } + + return result; +} + +// Restore this entry and corresponding DDE entry. +nsresult ProtocolRegistryEntry::reset() { + // Restore this entry. + nsresult rv = SavedRegistryEntry::reset(); + + // Do same for corresponding DDE entry (which we had to zap to stop DDE). + DDERegistryEntry( protocol ).reset(); + + // Special case. + if ( protocol = "http" ) { + // We had to zap HKR\Software\Classes\http\shell\open\ddeexec\Application + // (see comment above under ProtocolRegistryEntry::set). Restore it here. + SavedRegistryEntry( HKEY_LOCAL_MACHINE, "Software\\Classes\\http\\shell\\open\\ddeexec\\Application", NULL, NULL ).reset(); + } + return rv; +} + +// Return current setting for this registry entry. +nsCString RegistryEntry::currentSetting() const { + nsCString result; + + HKEY key; + LONG rc = ::RegOpenKey( baseKey, keyName, &key ); + if ( rc == ERROR_SUCCESS ) { + char buffer[4096]; + DWORD len = sizeof buffer; + rc = ::RegQueryValueEx( key, valueNameArg(), NULL, NULL, (LPBYTE)buffer, &len ); + if ( rc == ERROR_SUCCESS ) { + result = buffer; + } + ::RegCloseKey( key ); + } + + return result; +} + +// For each file extension, map it to this entry's file type. +// Set the file type so this application opens files of that type. +nsresult FileTypeRegistryEntry::set() { + nsresult rv = NS_OK; + + // Set file extensions. + for ( int i = 0; NS_SUCCEEDED( rv ) && ext[i]; i++ ) { + nsCString thisExt = "Software\\Classes\\"; + thisExt += ext[i]; + rv = SavedRegistryEntry( HKEY_LOCAL_MACHINE, thisExt, "", fileType ).set(); + } + + // If OK, set file type opener. + if ( NS_SUCCEEDED( rv ) ) { + rv = ProtocolRegistryEntry::set(); + + // If we just created this file type entry, set description and default icon. + if ( NS_SUCCEEDED( rv ) ) { + nsCString descKey = "Software\\Classes\\"; + descKey += protocol; + RegistryEntry descEntry( HKEY_LOCAL_MACHINE, descKey, NULL, desc ); + if ( descEntry.currentSetting().IsEmpty() ) { + descEntry.set(); + } + nsCString iconKey = "Software\\Classes\\"; + iconKey += protocol; + iconKey += "\\DefaultIcon"; + RegistryEntry iconEntry( HKEY_LOCAL_MACHINE, iconKey, NULL, thisApplication()+",1" ); + if ( iconEntry.currentSetting().IsEmpty() ) { + iconEntry.set(); + } + } + } + + return rv; +} + +// Basically, the inverse of set(). +// First, reset the opener for this entry's file type. +// Then, reset the file type associated with each extension. +nsresult FileTypeRegistryEntry::reset() { + nsresult rv = ProtocolRegistryEntry::reset(); + + for ( int i = 0; ext[ i ]; i++ ) { + nsCString thisExt = "Software\\Classes\\"; + thisExt += ext[i]; + (void)SavedRegistryEntry( HKEY_LOCAL_MACHINE, thisExt, "", fileType ).reset(); + } + + return rv; +} + +// Do inherited set() and also set key for edit (with -edit option). +// +// Note: We make the rash assumption that we "own" this filetype (aka "protocol"). +// If we ever start commandeering some other file type then this may have to be +// rethought. The solution is to override reset() and undo this (and make the +// "edit" entry a SavedRegistryEntry). +nsresult EditableFileTypeRegistryEntry::set() { + nsresult rv = FileTypeRegistryEntry::set(); + if ( NS_SUCCEEDED( rv ) ) { + nsCString editKey = "Software\\Classes\\"; + editKey += protocol; + editKey += "\\shell\\edit\\command"; + nsCString editor = thisApplication(); + editor += " -edit \"%1\""; + rv = RegistryEntry( HKEY_LOCAL_MACHINE, editKey, "", editor ).set(); + } + return rv; +} + +// Convert current registry setting to boolean. +BoolRegistryEntry::operator void*() { + return (void*)( currentSetting() == "1" ? PR_TRUE : PR_FALSE ); +}