/*
 *  Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "glib.h"
#include "js-console.h"
#include "gul-string.h"
#include "galeon-config.h"
#include "gtkmozembed.h"
#include "mozilla-embed-shell.h"
#include "mozilla-prefs.h"
#include "prefs-strings.h"
#include "mozilla-notifiers.h"
#include "mozilla-i18n.h"
#include "eel-gconf-extensions.h"
#include "galeon-embed-prefs.h"
#include "MozRegisterComponents.h"
#include "SideBar.h"
#include "nsIConsoleService.h"
#include "JSConsoleListener.h"
#include "nsIJSConsoleService.h"
#include "CookieObserver.h"
#include "mozilla-cookie.h"
#include "mozilla-encodings.h"

#include <time.h>
#include <glib/gi18n.h>
#include <string.h>
#include <nsICacheService.h>
#include <nsCOMPtr.h>
#include <nsNetCID.h>
#include <nsNetUtil.h>
#include <nsIServiceManager.h>
#include <nsIIOService.h>
#include <nsIProtocolProxyService.h>
#include <nsIJVMManager.h>
#include <nsIAtom.h>
#include <nsICharsetConverterManager.h>
#if MOZILLA_SNAPSHOT > 9
#include <nsIStringEnumerator.h>
#else
#include <nsICharsetConverterManager2.h>
#endif
#include <nsIFontEnumerator.h>
#include <nsISupportsPrimitives.h>
#include <nsReadableUtils.h>
#include <nsIPermissionManager.h>
#include <nsICookieManager.h>
#include <nsIPermission.h>
#include <nsIPasswordManager.h>
#include <nsIPassword.h>
#include <nsICookie.h>
#if MOZILLA_SNAPSHOT <= 12
#include <nsCCookieManager.h>
#endif
#include <nsCPasswordManager.h>
#include <nsIObserverService.h>
#include <nsIPrefService.h>

//For setting the locale. hopefully gtkmozembed will do itself soon
#if MOZILLA_SNAPSHOT > 13
#include <nsIChromeRegistry.h>
#else
#include <chrome/nsIChromeRegistry.h>
#endif
#include <locale/nsILocaleService.h>

#define MOZILLA_PROFILE_DIR  GALEON_DIR"/mozilla"
#define MOZILLA_PROFILE_NAME "galeon"
#define MOZILLA_PROFILE_FILE "prefs.js"

//Absolute path to the file holding default preferences
#ifndef DEFAULT_PROFILE_FILE
#define DEFAULT_PROFILE_FILE SHARE_DIR"/default-prefs.js"
#endif

#if MOZILLA_SNAPSHOT > 9
//Table of permission types to map to new string based api
const char* gPermType[3] = { "cookie", "image", "popup" };
#endif

static void
mozilla_embed_shell_class_init (MozillaEmbedShellClass *klass);
static void
mozilla_embed_shell_init (MozillaEmbedShell *ges);
static void
mozilla_embed_shell_finalize (GObject *object);

static gboolean
impl_initialize (GaleonEmbedShell *mes);

static void              
impl_get_capabilities (GaleonEmbedShell *shell,
		       EmbedShellCapabilities *caps);
static gresult      
impl_clear_cache (GaleonEmbedShell *shell,
		  CacheType type);
static gresult          
impl_set_offline_mode (GaleonEmbedShell *shell,
		       gboolean offline);
static gresult           
impl_load_proxy_autoconf (GaleonEmbedShell *shell,
			  const char* url);
static gresult           
impl_show_java_console (GaleonEmbedShell *shell);
static gresult           
impl_shell_show_js_console (GaleonEmbedShell *shell);
static gresult           
impl_get_encodings (GaleonEmbedShell *shell,
		    GaleonEncodings **encodings);
static gresult           
impl_get_font_langs (GaleonEmbedShell *shell,
		     GList **langs);
static gresult
impl_get_font_list (GaleonEmbedShell *shell,
		    const char *langGroup,
		    const char *fontType,
		    GList **fontList,
		    char **default_font);
static gresult           
impl_set_permission (GaleonEmbedShell *shell,
		     const char *url, 
		     PermissionType type,
		     gboolean allow);
static gresult           
impl_list_permissions (GaleonEmbedShell *shell,
		       PermissionType type, 
		       GList **permissions);
static gresult           
impl_remove_permissions (GaleonEmbedShell *shell,
		         PermissionType type,
		         GList *permissions);
static gresult           
impl_test_permission (GaleonEmbedShell *shell,
		      const char *url, 
		      PermissionType type,
		      PermissionActionType *ret_action);
static gresult
impl_list_cookies (GaleonEmbedShell *shell,
		   GList **cookies);
static gresult           
impl_remove_cookies (GaleonEmbedShell *shell,
		     GList *cookies,
		     gboolean block);
static gresult           
impl_list_passwords (GaleonEmbedShell *shell,
		     PasswordType type, 
		     GList **passwords);
static gresult           
impl_remove_passwords (GaleonEmbedShell *shell,
		       GList *passwords,
		       PasswordType type);

static void mozilla_embed_shell_new_window_orphan_cb (GtkMozEmbedSingle *embed,
            	           		              GtkMozEmbed **retval, 
					              guint chrome_mask,
                           		              GaleonEmbedShell *shell);

struct MozillaEmbedShellPrivate
{
	GaleonDialog *js_console;
	MozillaEncodings *encodings;
};

static NS_DEFINE_CID(kJVMManagerCID, NS_JVMMANAGER_CID);

GObject *mozilla_js_console;

static GObjectClass *parent_class = NULL;

GType
mozilla_embed_shell_get_type (void)
{
       static GType mozilla_embed_shell_type = 0;

        if (mozilla_embed_shell_type == 0)
        {
                static const GTypeInfo our_info =
                {
                        sizeof (MozillaEmbedShellClass),
                        NULL, /* base_init */
                        NULL, /* base_finalize */
                        (GClassInitFunc) mozilla_embed_shell_class_init,
                        NULL, /* class_finalize */
                        NULL, /* class_data */
                        sizeof (MozillaEmbedShell),
                        0,    /* n_preallocs */
                        (GInstanceInitFunc) mozilla_embed_shell_init
                };

                mozilla_embed_shell_type = g_type_register_static (GALEON_EMBED_SHELL_TYPE,
								   "MozillaEmbedShell",
								   &our_info, (GTypeFlags)0);
        }

        return mozilla_embed_shell_type;
}

static void
mozilla_embed_shell_class_init (MozillaEmbedShellClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	GaleonEmbedShellClass *shell_class;
	
	parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
	shell_class = GALEON_EMBED_SHELL_CLASS (klass);
	
        object_class->finalize = mozilla_embed_shell_finalize;

	shell_class->initialize = impl_initialize;
	shell_class->get_capabilities = impl_get_capabilities;
	shell_class->clear_cache = impl_clear_cache;
	shell_class->set_offline_mode = impl_set_offline_mode;
	shell_class->load_proxy_autoconf = impl_load_proxy_autoconf;
	shell_class->show_java_console = impl_show_java_console;
	shell_class->show_js_console = impl_shell_show_js_console;
	shell_class->get_encodings   = impl_get_encodings;
	shell_class->get_font_langs = impl_get_font_langs;
	shell_class->get_font_list = impl_get_font_list;
	shell_class->set_permission = impl_set_permission;
	shell_class->list_permissions = impl_list_permissions;
	shell_class->remove_permissions = impl_remove_permissions;
	shell_class->test_permission = impl_test_permission;
	shell_class->list_cookies = impl_list_cookies;
	shell_class->remove_cookies = impl_remove_cookies;
	shell_class->list_passwords = impl_list_passwords;
	shell_class->remove_passwords = impl_remove_passwords;
}

static gboolean
mozilla_set_default_prefs (void)
{
	nsCOMPtr<nsIPrefService> prefs
		= do_GetService (NS_PREFSERVICE_CONTRACTID);
	if (!prefs) return FALSE;

	// read our predefined default prefs
	nsresult rv;
	nsCOMPtr<nsILocalFile> file;
	rv = NS_NewNativeLocalFile(
		NS_LITERAL_CSTRING(DEFAULT_PROFILE_FILE),
		PR_TRUE, getter_AddRefs(file));
	if (NS_FAILED(rv)) return FALSE;

	rv = prefs->ReadUserPrefs (file);

	if (NS_FAILED(rv))
	{
		g_warning ("failed to read default preferences, error: %x", rv);
		return FALSE;
	}

	// Load the default user preferences as well.  This also makes the
	// prefs to be saved in the user's prefs.js file, instead of messing up
	// our global defaults file.
	rv = prefs->ReadUserPrefs (nsnull);
	if (NS_FAILED(rv)) 
	{
		g_warning ("failed to read user preferences, error: %x", rv);
	}

	nsCOMPtr<nsIPrefBranch> pref;
	prefs->GetDefaultBranch ("", getter_AddRefs(pref));
	if (!pref) return FALSE;

	// Search engine for keyword search, although disabled by default, set
	// here to facilitate l10n.
	pref->SetCharPref ("keyword.URL", _("http://www.google.com/search?ie=UTF-8&q="));

	// Also set vendor and vendorSub prefs so that mozilla can construct
	// the user agent string for us.
	pref->SetCharPref ("general.useragent.vendor", "Galeon");
	pref->SetCharPref ("general.useragent.vendorSub", VERSION);

	return TRUE;
}

static void
mozilla_init_single (MozillaEmbedShell *mes)
{	
	GtkMozEmbedSingle *single;
	
	/* get single */
        single = gtk_moz_embed_single_get ();
        if (single == NULL)
        {
                g_warning ("Failed to get singleton embed object!\n");
        }

        /* allow creation of orphan windows */
        g_signal_connect (G_OBJECT (single), "new_window_orphan",
                          GTK_SIGNAL_FUNC (mozilla_embed_shell_new_window_orphan_cb),
			  mes);
}

static void
mozilla_init_home (void)
{
	char *mozilla_five_home;
        mozilla_five_home = g_strdup (g_getenv ("MOZILLA_FIVE_HOME"));
        gtk_moz_embed_set_comp_path (mozilla_five_home);
        g_free (mozilla_five_home);
}

void
mozilla_init_profile (void)
{
	char *profile_path;
	profile_path = g_build_filename (g_get_home_dir (), 
					 MOZILLA_PROFILE_DIR, 
					 NULL);
        gtk_moz_embed_set_profile_path (profile_path, MOZILLA_PROFILE_NAME);
        g_free (profile_path);
}

static void
mozilla_init_js_console (MozillaEmbedShell *mes)
{
	nsCOMPtr<nsIConsoleService> consoleService = 
		do_GetService (NS_CONSOLESERVICE_CONTRACTID);
        g_return_if_fail (consoleService != nsnull);

        JSConsoleListener *listener = new JSConsoleListener();
        consoleService->RegisterListener (listener);
	
	mes->priv->js_console = js_console_new ();

	mozilla_js_console = G_OBJECT(mes->priv->js_console);
}

#if 0
static gboolean
have_gnome_url_handler (const gchar *protocol)
{
	gchar *key, *cmd;
	gboolean rv;

	key = g_strdup_printf ("/desktop/gnome/url-handlers/%s/command", 
			       protocol);
	cmd = eel_gconf_get_string (key);
	g_free (key);

	rv = (cmd != NULL);
	g_free (cmd);

	if (!rv) return rv;

	key = g_strdup_printf ("/desktop/gnome/url-handlers/%s/enabled", 
			       protocol);
	rv = eel_gconf_get_boolean (key);
	g_free (key);

	return rv;
}
#endif

static void
mozilla_register_external_protocols (void)
{
	/* FIXME register only when needed */
#if 0
	if (have_gnome_url_handler ("ftp"))
	{
		mozilla_register_FtpProtocolHandler ();
	}
	else
	{
		mozilla_unregister_FtpProtocolHandler ();
	}
#endif

	mozilla_register_MailtoProtocolHandler ();
}

static gboolean
mozilla_init_cookie_observer(void)
{
	//We new this observer but never delete it
	//This is ok as mozilla_embed_shell's lifetime is
	//the whole time galeon is running. Galeon exits 
	//when it is destroyed, so there's no real need to
	//clean up. 

	nsresult rv;

	nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1", &rv));
	if(NS_FAILED(rv) || ! os) return FALSE;

	GCookieObserver* cookieObserver = new GCookieObserver();

	rv = os->AddObserver(cookieObserver,
			     PERM_CHANGE_NOTIFICATION,
			     PR_FALSE);
	if (NS_FAILED(rv)) return FALSE;

	return TRUE;
}

static nsresult
getUILang(nsAString& aUILang)
{
	nsresult       result;
	// get a locale service
	nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &result);

	if (NS_FAILED (result) || !localeService)
	{
		g_warning ("Could not get locale service!\n");
		return NS_ERROR_FAILURE;
	}
        
#if MOZILLA_SNAPSHOT > 12
	result = localeService->GetLocaleComponentForUserAgent (aUILang);
#else
	nsXPIDLString uiLang;
	result = localeService->GetLocaleComponentForUserAgent(getter_Copies(uiLang));
	aUILang.Assign(uiLang);
#endif
	if (NS_FAILED (result))
	{
		g_warning ("Could not determine locale!\n");
		return result;
	}

	return NS_OK;
}
 
// update global locale if possible (in case when user-*.rdf can be updated)
// so that any apps after this can be invoked in the UILocale and contentLocale
static gboolean
mozilla_init_chrome (void)
{
	nsresult rv = NS_OK;
	nsAutoString uiLang;
	// compute lang code
	rv = getUILang(uiLang);
	if (NS_FAILED (rv)) return FALSE;

	nsCOMPtr<nsIXULChromeRegistry> chromeRegistry = do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
	if (NS_FAILED (rv) || !chromeRegistry)
	{
		g_warning ("Could not get the chrome registry!\n");
		return FALSE;
	}
	
	// set locale
	chromeRegistry->SetRuntimeProvider(PR_TRUE);

	// Dont worry if this fails, it is probably because the lang pack
	// isn't installed.
	chromeRegistry->SelectLocale (NS_ConvertUCS2toUTF8(uiLang), PR_FALSE);

	// Make sure skin is classic so we get native scrollbars
	rv = chromeRegistry->SelectSkin (NS_LITERAL_CSTRING("classic/1.0"), PR_FALSE);
	if (NS_FAILED (rv)) return FALSE;

	return TRUE;
}

static void
mozilla_embed_shell_init (MozillaEmbedShell *mes)
{
        mes->priv = g_new0 (MozillaEmbedShellPrivate, 1);

	mes->priv->encodings = NULL;

	/* Pre initialization */
	mozilla_init_home ();
	mozilla_init_profile ();
	
	/* Fire up the best */
	gtk_moz_embed_push_startup ();
}


static gboolean
impl_initialize (GaleonEmbedShell *ges)
{
	gboolean ret;
	MozillaEmbedShell *mes = MOZILLA_EMBED_SHELL(ges);

	/* Until gtkmozembed does this itself */
	ret = mozilla_init_chrome();
	if (ret == FALSE) return FALSE;

	/* Post initialization */
	ret = mozilla_set_default_prefs ();
	if (ret == FALSE) return FALSE;

	mozilla_notifiers_init (mes);

	mozilla_init_single (mes);
	
	ret = mozilla_register_components ();
	if (ret == FALSE) return FALSE;

	mozilla_init_js_console (mes);

	mozilla_register_external_protocols ();

	mozilla_init_sidebar ();

	mozilla_init_cookie_observer();
		
	return TRUE;
}

static void 
mozilla_embed_shell_new_window_orphan_cb (GtkMozEmbedSingle *embed,
                      		          GtkMozEmbed **retval, 
					  guint chrome_mask,
                           		  GaleonEmbedShell *shell)
{
	/* FIXME conversion duped in mozilla_embed */
	GaleonEmbed *new_embed;
	int i;
        EmbedChromeMask mask = EMBED_CHROME_OPENASPOPUP;
        
        struct
        {
                guint chromemask;
                EmbedChromeMask embed_mask;
        }
        conversion_map [] =
        {
                { GTK_MOZ_EMBED_FLAG_DEFAULTCHROME, EMBED_CHROME_DEFAULT },
                { GTK_MOZ_EMBED_FLAG_MENUBARON, EMBED_CHROME_MENUBARON },
                { GTK_MOZ_EMBED_FLAG_TOOLBARON, EMBED_CHROME_TOOLBARON },
                { GTK_MOZ_EMBED_FLAG_STATUSBARON, EMBED_CHROME_STATUSBARON },
                { GTK_MOZ_EMBED_FLAG_WINDOWRAISED, EMBED_CHROME_WINDOWRAISED },
                { GTK_MOZ_EMBED_FLAG_WINDOWLOWERED, EMBED_CHROME_WINDOWLOWERED },
                { GTK_MOZ_EMBED_FLAG_CENTERSCREEN, EMBED_CHROME_CENTERSCREEN },
                { GTK_MOZ_EMBED_FLAG_OPENASDIALOG, EMBED_CHROME_OPENASDIALOG },
                { GTK_MOZ_EMBED_FLAG_OPENASCHROME, EMBED_CHROME_OPENASCHROME },
                { 0, EMBED_CHROME_NONE }
        };

        for (i = 0; conversion_map[i].chromemask != 0; i++)
        {
                if (chrome_mask & conversion_map[i].chromemask)
                {
                        mask = (EmbedChromeMask) (mask | conversion_map[i].embed_mask); 
                }
        }
       
	g_signal_emit_by_name (shell, "new_window_orphan", &new_embed, mask);

	g_assert (new_embed != NULL);
	
	gtk_moz_embed_set_chrome_mask (GTK_MOZ_EMBED(new_embed), chrome_mask);

	*retval = GTK_MOZ_EMBED(GALEON_EMBED(new_embed));
}

static void
mozilla_embed_shell_finalize (GObject *object)
{
	MozillaEmbedShell *mes;

        g_return_if_fail (object != NULL);
        g_return_if_fail (IS_MOZILLA_EMBED_SHELL (object));

        mes = MOZILLA_EMBED_SHELL (object);

        g_return_if_fail (mes->priv != NULL);

	mozilla_notifiers_free ();

	mozilla_prefs_save ();
	
	gtk_moz_embed_pop_startup ();
	
	if (mes->priv->encodings)
	{
		g_object_unref (mes->priv->encodings);
	}
        g_free (mes->priv);

        G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void              
impl_get_capabilities (GaleonEmbedShell *shell,
		       EmbedShellCapabilities *caps)
{
	EmbedShellCapabilities mycaps;
	
	mycaps = (EmbedShellCapabilities)
	 	 (CACHE_CLEAR_CAP |
	          OFFLINE_CAP |
        	  PROXY_AUTOCONF_CAP |
	          JAVA_CONSOLE_CAP |
	          JS_CONSOLE_CAP |
	          CHARSETS_CAP |
	          PERMISSIONS_CAP |
	          COOKIES_CAP |
	          PASSWORDS_CAP);
	
	*caps = mycaps;
}

static gresult      
impl_clear_cache (GaleonEmbedShell *shell,
		  CacheType type)
{
	nsresult rv;
	
	nsCOMPtr<nsICacheService> CacheService =
                        do_GetService (NS_CACHESERVICE_CONTRACTID, &rv);
	if (NS_FAILED(rv)) return G_FAILED;

	CacheService->EvictEntries((guint)type);

	return G_OK;
}

static gresult          
impl_set_offline_mode (GaleonEmbedShell *shell,
		       gboolean offline)
{
	nsresult rv;

	nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
        if (NS_FAILED(rv))
                return G_FAILED;

        rv = io->SetOffline(offline);
	if (NS_SUCCEEDED(rv)) return G_FAILED;
	
	return G_OK;
}

static gresult           
impl_load_proxy_autoconf (GaleonEmbedShell *shell,
			  const char* url)
{
	nsresult rv;

        nsCOMPtr<nsIProtocolProxyService> pps =
                do_GetService ("@mozilla.org/network/protocol-proxy-service;1",
                               &rv);
        if (NS_FAILED(rv) || !pps) return G_FAILED;

        rv = pps->ConfigureFromPAC (url);
	if (NS_FAILED(rv)) return G_FAILED;
	
	return G_OK;
}

static gresult           
impl_show_java_console (GaleonEmbedShell *shell)
{
	nsresult rv;
        nsCOMPtr<nsIJVMManager> JVMManager = do_GetService (kJVMManagerCID,
                                                            &rv);
        if (NS_FAILED(rv)) return G_FAILED;

        rv = JVMManager->ShowJavaConsole ();
	if (NS_FAILED(rv)) return G_FAILED;
	
	return G_OK;
}

static gresult           
impl_shell_show_js_console (GaleonEmbedShell *shell)
{
	nsresult rv;
        nsCOMPtr<nsIJSConsoleService> JSConsoleService =
                do_GetService ("@mozilla.org/embedcomp/jsconsole-service;1",
                               &rv);
        if (NS_FAILED(rv)) return G_FAILED;

        rv = JSConsoleService->Open (nsnull);
	if (NS_FAILED(rv)) return G_FAILED;

	return G_OK;
}

static gresult           
impl_get_encodings (GaleonEmbedShell *shell,
		    GaleonEncodings **encodings)
{
	MozillaEmbedShell *mshell = MOZILLA_EMBED_SHELL(shell);

	if (! mshell->priv->encodings)
	{
		mshell->priv->encodings = mozilla_encodings_new ();
	}
	*encodings = GALEON_ENCODINGS (mshell->priv->encodings);
	return G_OK;
}


static gresult
impl_get_font_langs (GaleonEmbedShell *shell,
		     GList **langs)
{
	GList *l = NULL;
	int i;
	for (i = 0; i < num_font_languages; i++)
	{
		FontLangInfo *info = g_new0 (FontLangInfo, 1);
		info->key   = font_languages[i].key;
		info->title = _(font_languages[i].title);
		l = g_list_append (l, info);
	}
	*langs = l;
	return G_OK;
}


static gresult
impl_get_font_list (GaleonEmbedShell *shell,
		    const char *langGroup,
		    const char *fontType,
		    GList **fontList,
		    char **default_font)
{
	nsresult rv;

	nsCOMPtr<nsIFontEnumerator> mozFontEnumerator;
	mozFontEnumerator = do_CreateInstance("@mozilla.org/gfx/fontenumerator;1", &rv);
	NS_ENSURE_SUCCESS(rv, G_FAILED);

	PRUint32    n_fonts;
	PRUnichar **fonts;
	rv = mozFontEnumerator->EnumerateFonts (langGroup, fontType,
			                        &n_fonts, &fonts);
	NS_ENSURE_SUCCESS(rv, G_FAILED);

	GList *l = NULL;
	for (PRUint32 i = 0; i < n_fonts; i++)
	{
		char *str;

		str = g_strdup (NS_ConvertUCS2toUTF8(fonts[i]).get());
		l = g_list_prepend (l, str);
		nsMemory::Free (fonts[i]);
	}

	nsMemory::Free (fonts);

	*fontList = g_list_reverse (l);

	if (default_font != NULL)
	{
		char key [255];

		sprintf (key, "font.name.%s.%s", fontType, langGroup);
		
		*default_font = mozilla_prefs_get_string (key);
	}

	return G_OK;
}

static gresult           
impl_set_permission(GaleonEmbedShell *shell,
		    const char *url, 
		    PermissionType type,
		    gboolean allow)
{
	nsresult rv;
	nsCOMPtr<nsIPermissionManager> permissionManager =
                        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);

	nsCOMPtr<nsIURI> uri;
	rv = NS_NewURI(getter_AddRefs(uri), url);
	if (NS_FAILED(rv) || !uri) return G_FAILED;

	#if MOZILLA_SNAPSHOT > 9
	rv = permissionManager->Add(uri, gPermType[type],
	#else
	rv = permissionManager->Add(uri, type,
	#endif
				    allow ? (PRUint32)nsIPermissionManager::ALLOW_ACTION
				    	  : (PRUint32)nsIPermissionManager::DENY_ACTION);

	if (NS_FAILED(rv)) return G_FAILED;

	return G_OK;
}

static gresult           
impl_list_permissions (GaleonEmbedShell *shell,
		       PermissionType type, 
		       GList **permissions)
{
        nsresult result;

	*permissions = NULL;
	
	nsCOMPtr<nsIPermissionManager> permissionManager = 
                        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
        nsCOMPtr<nsISimpleEnumerator> permissionEnumerator;
        result = permissionManager->GetEnumerator(getter_AddRefs(permissionEnumerator));
        if (NS_FAILED(result)) return G_FAILED;
	
        PRBool enumResult;
        for (permissionEnumerator->HasMoreElements(&enumResult) ;
             enumResult == PR_TRUE ;
             permissionEnumerator->HasMoreElements(&enumResult))
        {
                nsCOMPtr<nsIPermission> nsPermission;
                result = permissionEnumerator->GetNext(getter_AddRefs(nsPermission));
                if (NS_FAILED(result)) return G_FAILED;

#if MOZILLA_SNAPSHOT > 9
		nsCAutoString cType;
		nsPermission->GetType(cType);
		if (cType.Equals(gPermType[type]))
#else
		PRUint32 cType;
                nsPermission->GetType(&cType);
                if ((PRUint32)cType == (PRUint32)type)
#endif
                {
                        PermissionInfo *b = g_new0(PermissionInfo, 1);
			nsCString host;
			nsPermission->GetHost(host);
			b->domain = g_strdup(host.get());

			PRUint32 cap;
			nsPermission->GetCapability(&cap);
			switch (cap)
			{
			  case nsIPermissionManager::ALLOW_ACTION :
			  	b->status = TRUE;
			  	break;
			  case nsIPermissionManager::DENY_ACTION :
			 	b->status = FALSE;
			 	break;
			  default :
			  	b->status = FALSE;
			}
                        *permissions = g_list_prepend(*permissions, b);
                }
        }

        *permissions = g_list_reverse(*permissions);
	
	return G_OK;
}

static gresult           
impl_remove_permissions(GaleonEmbedShell *shell,
		        PermissionType type,
		        GList *permissions)
{
	nsresult result;
        nsCOMPtr<nsIPermissionManager> permissionManager =
                        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);

        for (GList *l = permissions; l != NULL; l = l->next)
        {
                PermissionInfo *b = (PermissionInfo *)l->data;
                result = permissionManager->Remove(nsDependentCString(b->domain),
#if MOZILLA_SNAPSHOT > 9
						   gPermType[type]);
#else
                				   type);
#endif
                if (NS_FAILED(result)) return G_FAILED;
        };

	return G_OK;
}

static gresult           
impl_test_permission (GaleonEmbedShell *shell,
		      const char *url, 
		      PermissionType type,
		      PermissionActionType *ret_action)
{
	nsresult rv;
	nsCOMPtr<nsIPermissionManager> permissionManager =
                        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);

	if (!url) return G_FAILED;

	nsCOMPtr<nsIURI> uri;
	rv = NS_NewURI(getter_AddRefs(uri), url);
	if (NS_FAILED(rv) || !uri) return G_FAILED;

	PRUint32 action;
#if MOZILLA_SNAPSHOT > 9
	rv = permissionManager->TestPermission(uri, gPermType[type], &action);
#else
	rv = permissionManager->TestPermission(uri, type, &action);
#endif

	switch (action)
	{
	  case nsIPermissionManager::UNKNOWN_ACTION :
	  	*ret_action = UNKNOWN_ACTION;
	  	break;
	  case nsIPermissionManager::ALLOW_ACTION :
	  	*ret_action = ALLOW_ACTION;
	  	break;
	  case nsIPermissionManager::DENY_ACTION :
	  	*ret_action = DENY_ACTION;
	  	break;
	}
	if (NS_FAILED(rv)) return G_FAILED;

	return G_OK;
}

static gresult           
impl_list_cookies (GaleonEmbedShell *shell,
		   GList **cookies)
{
        nsresult result;
        nsCOMPtr<nsICookieManager> cookieManager = 
                        do_GetService(NS_COOKIEMANAGER_CONTRACTID);
        nsCOMPtr<nsISimpleEnumerator> cookieEnumerator;
        result = 
            cookieManager->GetEnumerator(getter_AddRefs(cookieEnumerator));
        if (NS_FAILED(result)) return G_FAILED;

        PRBool enumResult;
        for (cookieEnumerator->HasMoreElements(&enumResult) ;
             enumResult == PR_TRUE ;
             cookieEnumerator->HasMoreElements(&enumResult))
        {
                nsCOMPtr<nsICookie> nsCookie;
                result = cookieEnumerator->GetNext(getter_AddRefs(nsCookie));
                if (NS_FAILED(result)) return G_FAILED;

                CookieInfo *c = mozilla_cookie_to_info(nsCookie);
                *cookies = g_list_prepend(*cookies, c);
        }       

	*cookies = g_list_reverse(*cookies);
		
	return G_OK;
}

static gresult           
impl_remove_cookies (GaleonEmbedShell *shell,
		     GList *cookies,
		     gboolean block)
{
	nsresult result;
        nsCOMPtr<nsICookieManager> cookieManager =
                        do_GetService(NS_COOKIEMANAGER_CONTRACTID);
	
        for (GList *l = cookies; l != NULL; l = l->next)
        {
                CookieInfo *c = (CookieInfo *)l->data;

                result = cookieManager->Remove (nsDependentCString(c->domain),
                                                nsDependentCString(c->name),
                                                nsDependentCString(c->path),
                                                block);
                if (NS_FAILED(result)) return G_FAILED;
        };

	return G_OK;
}
	
static gresult           
impl_list_passwords (GaleonEmbedShell *shell,
		     PasswordType type, 
		     GList **passwords)
{
        nsresult result = NS_ERROR_FAILURE;

        nsCOMPtr<nsIPasswordManager> passwordManager =
                        do_GetService(NS_PASSWORDMANAGER_CONTRACTID);
        nsCOMPtr<nsISimpleEnumerator> passwordEnumerator;
        if (type == PASSWORD_PASSWORD)
                result = passwordManager->GetEnumerator 
                                (getter_AddRefs(passwordEnumerator));
        else if (type == PASSWORD_REJECT)
                result = passwordManager->GetRejectEnumerator 
                                (getter_AddRefs(passwordEnumerator));
        if (NS_FAILED(result)) return G_FAILED;      

        PRBool enumResult;
        for (passwordEnumerator->HasMoreElements(&enumResult) ;
             enumResult == PR_TRUE ;
             passwordEnumerator->HasMoreElements(&enumResult))
        {
                nsCOMPtr<nsIPassword> nsPassword;
                result = passwordEnumerator->GetNext 
                                        (getter_AddRefs(nsPassword));
                if (NS_FAILED(result)) return G_FAILED;

                PasswordInfo *p = g_new0 (PasswordInfo, 1);

                nsCAutoString transfer;
                nsPassword->GetHost (transfer);
                p->host = g_strdup (transfer.get());

                if (type == PASSWORD_PASSWORD)
                {
                        nsAutoString unicodeName;
                        nsPassword->GetUser (unicodeName);
                        p->username = g_strdup(NS_ConvertUCS2toUTF8(unicodeName).get());
                }

		*passwords = g_list_prepend (*passwords, p);
        }       

	*passwords = g_list_reverse (*passwords);

	return G_OK;
}

static gresult           
impl_remove_passwords (GaleonEmbedShell *shell,
		       GList *passwords, 
		       PasswordType type)
{
	nsresult result = NS_ERROR_FAILURE;
        nsCOMPtr<nsIPasswordManager> passwordManager =
                        do_GetService(NS_PASSWORDMANAGER_CONTRACTID);

        for (GList *l = passwords; l != NULL; l = l->next)
        {
                PasswordInfo *p = (PasswordInfo *)l->data;
                if (type == PASSWORD_PASSWORD)
                {
                        result = passwordManager->RemoveUser (nsDependentCString(p->host),
                                                              NS_ConvertUTF8toUCS2(nsDependentCString(p->username)));
                }
                else if (type == PASSWORD_REJECT)
                {
                        result = passwordManager->RemoveReject
                                        (nsDependentCString(p->host));
                };

                if (NS_FAILED(result)) return G_FAILED;
        };
	
        return G_OK;
}

