Back to index

lightning-sunbird  0.9+nobinonly
nsGNOMERegistry.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 the GNOME helper app implementation.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * IBM Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2003
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Brian Ryner <bryner@brianryner.com>  (Original Author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 "nsGNOMERegistry.h"
00040 #include "prlink.h"
00041 #include "prmem.h"
00042 #include "nsString.h"
00043 #include "nsIComponentManager.h"
00044 #include "nsILocalFile.h"
00045 #include "nsMIMEInfoImpl.h"
00046 #include "nsAutoPtr.h"
00047 
00048 #include <glib.h>
00049 #include <glib-object.h>
00050 
00051 static PRLibrary *gconfLib;
00052 static PRLibrary *gnomeLib;
00053 static PRLibrary *vfsLib;
00054 
00055 typedef struct _GConfClient GConfClient;
00056 typedef struct _GnomeProgram GnomeProgram;
00057 typedef struct _GnomeModuleInfo GnomeModuleInfo;
00058 
00059 typedef struct {
00060   char *id;
00061   char *name;
00062   char *command;
00063   /* there is more here, but we don't need it */
00064 } GnomeVFSMimeApplication;
00065 
00066 typedef GConfClient * (*_gconf_client_get_default_fn)();
00067 typedef gchar * (*_gconf_client_get_string_fn)(GConfClient *,
00068                                           const char *, GError **);
00069 typedef gboolean (*_gconf_client_get_bool_fn)(GConfClient *,
00070                                               const char *, GError **);
00071 typedef gboolean (*_gnome_url_show_fn)(const char *, GError **);
00072 typedef const char * (*_gnome_vfs_mime_type_from_name_fn)(const char *);
00073 typedef GList * (*_gnome_vfs_mime_get_extensions_list_fn)(const char *);
00074 typedef void (*_gnome_vfs_mime_extensions_list_free_fn)(GList *);
00075 typedef const char * (*_gnome_vfs_mime_get_description_fn)(const char *);
00076 typedef GnomeVFSMimeApplication * (*_gnome_vfs_mime_get_default_application_fn)
00077                                                                 (const char *);
00078 typedef void (*_gnome_vfs_mime_application_free_fn)(GnomeVFSMimeApplication *);
00079 typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
00080                                            const GnomeModuleInfo *, int,
00081                                            char **, const char *, ...);
00082 typedef const GnomeModuleInfo * (*_libgnome_module_info_get_fn)();
00083 typedef GnomeProgram * (*_gnome_program_get_fn)();
00084 
00085 #define DECL_FUNC_PTR(func) static _##func##_fn _##func
00086 
00087 DECL_FUNC_PTR(gconf_client_get_default);
00088 DECL_FUNC_PTR(gconf_client_get_string);
00089 DECL_FUNC_PTR(gconf_client_get_bool);
00090 DECL_FUNC_PTR(gnome_url_show);
00091 DECL_FUNC_PTR(gnome_vfs_mime_type_from_name);
00092 DECL_FUNC_PTR(gnome_vfs_mime_get_extensions_list);
00093 DECL_FUNC_PTR(gnome_vfs_mime_extensions_list_free);
00094 DECL_FUNC_PTR(gnome_vfs_mime_get_description);
00095 DECL_FUNC_PTR(gnome_vfs_mime_get_default_application);
00096 DECL_FUNC_PTR(gnome_vfs_mime_application_free);
00097 DECL_FUNC_PTR(gnome_program_init);
00098 DECL_FUNC_PTR(libgnome_module_info_get);
00099 DECL_FUNC_PTR(gnome_program_get);
00100 
00101 static void
00102 CleanUp()
00103 {
00104   // Unload all libraries
00105   if (gnomeLib)
00106     PR_UnloadLibrary(gnomeLib);
00107   if (gconfLib)
00108     PR_UnloadLibrary(gconfLib);
00109   if (vfsLib)
00110     PR_UnloadLibrary(vfsLib);
00111 
00112   gnomeLib = gconfLib = vfsLib = nsnull;
00113 }
00114 
00115 static PRLibrary *
00116 LoadVersionedLibrary(const char* libName, const char* libVersion)
00117 {
00118   char *platformLibName = PR_GetLibraryName(nsnull, libName);
00119   nsCAutoString versionLibName(platformLibName);
00120   versionLibName.Append(libVersion);
00121   PR_Free(platformLibName);
00122   return PR_LoadLibrary(versionLibName.get());
00123 }
00124 
00125 /* static */ void
00126 nsGNOMERegistry::Startup()
00127 {
00128   #define ENSURE_LIB(lib) \
00129     PR_BEGIN_MACRO \
00130     if (!lib) { \
00131       CleanUp(); \
00132       return; \
00133     } \
00134     PR_END_MACRO
00135 
00136   #define GET_LIB_FUNCTION(lib, func) \
00137     PR_BEGIN_MACRO \
00138     _##func = (_##func##_fn) PR_FindFunctionSymbol(lib##Lib, #func); \
00139     if (!_##func) { \
00140       CleanUp(); \
00141       return; \
00142     } \
00143     PR_END_MACRO
00144 
00145   // Attempt to open libgconf
00146   gconfLib = LoadVersionedLibrary("gconf-2", ".4");
00147   ENSURE_LIB(gconfLib);
00148 
00149   GET_LIB_FUNCTION(gconf, gconf_client_get_default);
00150   GET_LIB_FUNCTION(gconf, gconf_client_get_string);
00151   GET_LIB_FUNCTION(gconf, gconf_client_get_bool);
00152 
00153   // Attempt to open libgnome
00154   gnomeLib = LoadVersionedLibrary("gnome-2", ".0");
00155   ENSURE_LIB(gnomeLib);
00156 
00157   GET_LIB_FUNCTION(gnome, gnome_url_show);
00158   GET_LIB_FUNCTION(gnome, gnome_program_init);
00159   GET_LIB_FUNCTION(gnome, libgnome_module_info_get);
00160   GET_LIB_FUNCTION(gnome, gnome_program_get);
00161 
00162   // Attempt to open libgnomevfs
00163   vfsLib = LoadVersionedLibrary("gnomevfs-2", ".0");
00164   ENSURE_LIB(vfsLib);
00165 
00166   GET_LIB_FUNCTION(vfs, gnome_vfs_mime_type_from_name);
00167   GET_LIB_FUNCTION(vfs, gnome_vfs_mime_get_extensions_list);
00168   GET_LIB_FUNCTION(vfs, gnome_vfs_mime_extensions_list_free);
00169   GET_LIB_FUNCTION(vfs, gnome_vfs_mime_get_description);
00170   GET_LIB_FUNCTION(vfs, gnome_vfs_mime_get_default_application);
00171   GET_LIB_FUNCTION(vfs, gnome_vfs_mime_application_free);
00172 
00173   // Initialize GNOME, if it's not already initialized.  It's not
00174   // necessary to tell GNOME about our actual command line arguments.
00175 
00176   if (!_gnome_program_get()) {
00177     char *argv[1] = { "gecko" };
00178     _gnome_program_init("Gecko", "1.0", _libgnome_module_info_get(),
00179                         1, argv, NULL);
00180   }
00181 
00182   // Note: after GNOME has been initialized, do not ever unload these
00183   // libraries.  They register atexit handlers, so if they are unloaded, we'll
00184   // crash on exit.
00185 }
00186 
00197 static gchar* getAppForScheme(const nsACString& aProtocolScheme)
00198 {
00199   if (!gconfLib)
00200     return nsnull;
00201 
00202   GConfClient *client = _gconf_client_get_default();
00203   NS_ASSERTION(client, "no gconf client");
00204 
00205   nsCAutoString gconfPath(NS_LITERAL_CSTRING("/desktop/gnome/url-handlers/") +
00206                           aProtocolScheme +
00207                           NS_LITERAL_CSTRING("/command"));
00208 
00209   gchar *app = _gconf_client_get_string(client, gconfPath.get(), NULL);
00210   g_object_unref(G_OBJECT(client));
00211 
00212   return app;
00213 }
00214 
00215 /* static */ PRBool
00216 nsGNOMERegistry::HandlerExists(const char *aProtocolScheme)
00217 {
00218   gchar *app = getAppForScheme(nsDependentCString(aProtocolScheme));
00219 
00220   if (app) {
00221     g_free(app);
00222     GConfClient *client = _gconf_client_get_default();
00223 
00224     nsCAutoString enabledPath(NS_LITERAL_CSTRING("/desktop/gnome/url-handlers/") +
00225                               nsDependentCString(aProtocolScheme) +
00226                               NS_LITERAL_CSTRING("/enabled"));
00227     gboolean isEnabled = _gconf_client_get_bool(client, enabledPath.get(), NULL);
00228 
00229     g_object_unref(G_OBJECT(client));
00230 
00231     return isEnabled ? PR_TRUE : PR_FALSE;
00232   }
00233 
00234   return PR_FALSE;
00235 }
00236 
00237 /* static */ nsresult
00238 nsGNOMERegistry::LoadURL(nsIURI *aURL)
00239 {
00240   if (!gconfLib)
00241     return NS_ERROR_FAILURE;
00242 
00243   nsCAutoString spec;
00244   aURL->GetAsciiSpec(spec);
00245 
00246   // XXX what if gnome_url_show() uses the default handler and that's us?
00247 
00248   if (_gnome_url_show(spec.get(), NULL))
00249     return NS_OK;
00250 
00251   return NS_ERROR_FAILURE;
00252 }
00253 
00254 /* static */ void
00255 nsGNOMERegistry::GetAppDescForScheme(const nsACString& aScheme,
00256                                      nsAString& aDesc)
00257 {
00258   char *app = getAppForScheme(aScheme);
00259 
00260   if (app) {
00261     CopyUTF8toUTF16(app, aDesc);
00262     g_free(app);
00263   }
00264 }
00265 
00266 
00267 /* static */ already_AddRefed<nsMIMEInfoBase>
00268 nsGNOMERegistry::GetFromExtension(const char *aFileExt)
00269 {
00270   if (!gconfLib)
00271     return nsnull;
00272 
00273   // Get the MIME type from the extension, then call GetFromType to
00274   // fill in the MIMEInfo.
00275 
00276   nsCAutoString fileExtToUse;
00277   if (aFileExt && aFileExt[0] != '.')
00278     fileExtToUse = '.';
00279 
00280   fileExtToUse.Append(aFileExt);
00281 
00282   const char *mimeType = _gnome_vfs_mime_type_from_name(fileExtToUse.get());
00283   if (!strcmp(mimeType, "application/octet-stream"))
00284     return nsnull;
00285 
00286   return GetFromType(mimeType);
00287 }
00288 
00289 /* static */ already_AddRefed<nsMIMEInfoBase>
00290 nsGNOMERegistry::GetFromType(const char *aMIMEType)
00291 {
00292   if (!gconfLib)
00293     return nsnull;
00294 
00295   GnomeVFSMimeApplication *handlerApp = _gnome_vfs_mime_get_default_application(aMIMEType);
00296   if (!handlerApp)
00297     return nsnull;
00298 
00299   nsRefPtr<nsMIMEInfoImpl> mimeInfo = new nsMIMEInfoImpl(aMIMEType);
00300   NS_ENSURE_TRUE(mimeInfo, nsnull);
00301 
00302   // Get the list of extensions and append then to the mimeInfo.
00303   GList *extensions = _gnome_vfs_mime_get_extensions_list(aMIMEType);
00304   for (GList *extension = extensions; extension; extension = extension->next)
00305     mimeInfo->AppendExtension(nsDependentCString((const char *) extension->data));
00306 
00307   _gnome_vfs_mime_extensions_list_free(extensions);
00308 
00309   const char *description = _gnome_vfs_mime_get_description(aMIMEType);
00310   mimeInfo->SetDescription(NS_ConvertUTF8toUCS2(description));
00311 
00312   // Convert UTF-8 registry value to filesystem encoding, which
00313   // g_find_program_in_path() uses.
00314 
00315   gchar *nativeCommand = g_filename_from_utf8(handlerApp->command,
00316                                               -1, NULL, NULL, NULL);
00317   if (!nativeCommand) {
00318     NS_ERROR("Could not convert helper app command to filesystem encoding");
00319     _gnome_vfs_mime_application_free(handlerApp);
00320     return nsnull;
00321   }
00322 
00323   gchar *commandPath = g_find_program_in_path(nativeCommand);
00324 
00325   g_free(nativeCommand);
00326 
00327   if (!commandPath) {
00328     _gnome_vfs_mime_application_free(handlerApp);
00329     return nsnull;
00330   }
00331 
00332   nsCOMPtr<nsILocalFile> appFile;
00333   NS_NewNativeLocalFile(nsDependentCString(commandPath), PR_TRUE,
00334                         getter_AddRefs(appFile));
00335   if (appFile) {
00336     mimeInfo->SetDefaultApplication(appFile);
00337     mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUCS2(handlerApp->name));
00338     mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
00339   }
00340 
00341   g_free(commandPath);
00342 
00343   _gnome_vfs_mime_application_free(handlerApp);
00344 
00345   nsMIMEInfoBase* retval;
00346   NS_ADDREF((retval = mimeInfo));
00347   return retval;
00348 }