/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 tw=80 et cindent: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla 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/MPL/ * * 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 * Christopher Blizzard. * * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Christopher Blizzard * Ramiro Estrugo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include "gtkmozembed.h" #include "gtkmozembed_common.h" #include "gtkmozembedprivate.h" #include "gtkmozembed_internal.h" #include "EmbedPrivate.h" #include "EmbedWindow.h" #ifdef MOZ_GTKPASSWORD_INTERFACE #include "EmbedPasswordMgr.h" #include "nsIPassword.h" #endif #include "EmbedGlobalHistory.h" //#include "EmbedDownloadMgr.h" // so we can do our get_nsIWebBrowser later... #include "nsIWebBrowser.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIPref.h" #include "nsICookieManager.h" #include "nsIPermissionManager.h" #include "nsNetCID.h" #include "nsICookie.h" #include "nsIX509Cert.h" // for strings #ifdef MOZILLA_INTERNAL_API #include "nsXPIDLString.h" #include "nsReadableUtils.h" #include "nsString.h" #else #include "nsStringAPI.h" #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #endif // for plugins #include "nsIDOMNavigator.h" #include "nsIDOMPluginArray.h" #include "nsIDOMPlugin.h" #include #include "nsIDOMMimeType.h" #include "nsIObserverService.h" //for security #include "nsIWebProgressListener.h" //for cache #include "nsICacheService.h" #include "nsICache.h" #include "gtkmozembedmarshal.h" #define NEW_TOOLKIT_STRING(x) g_strdup(NS_ConvertUTF16toUTF8(x).get()) #define GET_TOOLKIT_STRING(x) NS_ConvertUTF16toUTF8(x).get() #define GET_OBJECT_CLASS_TYPE(x) G_OBJECT_CLASS_TYPE(x) #define UNACCEPTABLE_CRASHY_GLIB_ALLOCATION(newed) PR_BEGIN_MACRO \ /* OOPS this code is using a glib allocation function which \ * will cause the application to crash when it runs out of \ * memory. This is not cool. either g_try methods should be \ * used or malloc, or new (note that gecko /will/ be replacing \ * its operator new such that new will not throw exceptions). \ * XXX please fix me. \ */ \ if (!newed) { \ } \ PR_END_MACRO #define ALLOC_NOT_CHECKED(newed) PR_BEGIN_MACRO \ /* This might not crash, but the code probably isn't really \ * designed to handle it, perhaps the code should be fixed? \ */ \ if (!newed) { \ } \ PR_END_MACRO // CID used to get the plugin manager static NS_DEFINE_CID(kPluginManagerCID, NS_PLUGINMANAGER_CID); // class and instance initialization static void gtk_moz_embed_common_class_init(GtkMozEmbedCommonClass *klass); static void gtk_moz_embed_common_init(GtkMozEmbedCommon *embed); static GtkObjectClass *common_parent_class = NULL; // GtkObject methods static void gtk_moz_embed_common_destroy(GtkObject *object); guint moz_embed_common_signals[COMMON_LAST_SIGNAL] = { 0 }; // GtkObject + class-related functions GtkType gtk_moz_embed_common_get_type(void) { static GtkType moz_embed_common_type = 0; if (!moz_embed_common_type) { static const GtkTypeInfo moz_embed_common_info = { "GtkMozEmbedCommon", sizeof(GtkMozEmbedCommon), sizeof(GtkMozEmbedCommonClass), (GtkClassInitFunc)gtk_moz_embed_common_class_init, (GtkObjectInitFunc)gtk_moz_embed_common_init, 0, 0, 0 }; moz_embed_common_type = gtk_type_unique(GTK_TYPE_BIN, &moz_embed_common_info); } return moz_embed_common_type; } static void gtk_moz_embed_common_class_init(GtkMozEmbedCommonClass *klass) { GtkObjectClass *object_class; object_class = GTK_OBJECT_CLASS(klass); common_parent_class = (GtkObjectClass *)gtk_type_class(gtk_object_get_type()); object_class->destroy = gtk_moz_embed_common_destroy; moz_embed_common_signals[COMMON_CERT_ERROR] = gtk_signal_new("certificate-error", GTK_RUN_LAST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, certificate_error), gtkmozembed_BOOL__POINTER_UINT, G_TYPE_BOOLEAN, 2, GTK_TYPE_POINTER, GTK_TYPE_UINT); moz_embed_common_signals[COMMON_SELECT_LOGIN] = gtk_signal_new("select-login", GTK_RUN_LAST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, select_login), gtk_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); moz_embed_common_signals[COMMON_REMEMBER_LOGIN] = gtk_signal_new("remember-login", GTK_RUN_LAST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, remember_login), gtkmozembed_INT__VOID, G_TYPE_INT, 0); // set up our signals moz_embed_common_signals[COMMON_ASK_COOKIE] = gtk_signal_new("ask-cookie", GTK_RUN_FIRST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, ask_cookie), gtkmozembed_VOID__POINTER_INT_STRING_STRING_STRING_STRING_STRING_BOOLEAN_INT, G_TYPE_NONE, 9, GTK_TYPE_POINTER, GTK_TYPE_INT, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_BOOL, GTK_TYPE_INT); /* moz_embed_common_signals[COMMON_CERT_DIALOG] = gtk_signal_new("certificate-dialog", GTK_RUN_LAST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, certificate_dialog), gtk_marshal_BOOL__POINTER, G_TYPE_BOOLEAN, 1, GTK_TYPE_POINTER); moz_embed_common_signals[COMMON_CERT_PASSWD_DIALOG] = gtk_signal_new("certificate-password-dialog", GTK_RUN_FIRST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, certificate_password_dialog), gtkmozembed_VOID__STRING_STRING_POINTER, G_TYPE_NONE, 3, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, GTK_TYPE_POINTER); moz_embed_common_signals[COMMON_CERT_DETAILS_DIALOG] = gtk_signal_new("certificate-details", GTK_RUN_FIRST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, certificate_details), gtk_marshal_VOID__POINTER, G_TYPE_NONE, 1, GTK_TYPE_POINTER); moz_embed_common_signals[COMMON_HISTORY_ADDED] = gtk_signal_new("global-history-item-added", GTK_RUN_FIRST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, history_added), gtk_marshal_VOID__STRING, G_TYPE_NONE, 1, GTK_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE); moz_embed_common_signals[COMMON_ON_SUBMIT_SIGNAL] = gtk_signal_new("on-submit", GTK_RUN_LAST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, on_submit), gtkmozembed_INT__VOID, G_TYPE_INT, 0); moz_embed_common_signals[COMMON_MODAL_DIALOG] = gtk_signal_new("modal_dialog", GTK_RUN_LAST, GET_OBJECT_CLASS_TYPE(klass), GTK_SIGNAL_OFFSET(GtkMozEmbedCommonClass, modal_dialog), gtkmozembed_INT__STRING_STRING_INT_INT_INT_INT, G_TYPE_INT, 6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); */ } static void gtk_moz_embed_common_init(GtkMozEmbedCommon *common) { // this is a placeholder for later in case we need to stash data at // a later data and maintain backwards compatibility. common->data = nsnull; EmbedCommon *priv = EmbedCommon::GetInstance(); priv->mCommon = GTK_OBJECT(common); common->data = priv; EmbedGlobalHistory::GetInstance(); } static void gtk_moz_embed_common_destroy(GtkObject *object) { g_return_if_fail(object != NULL); g_return_if_fail(GTK_IS_MOZ_EMBED_COMMON(object)); GtkMozEmbedCommon *embed = nsnull; EmbedCommon *commonPrivate = nsnull; embed = GTK_MOZ_EMBED_COMMON(object); commonPrivate = (EmbedCommon *)embed->data; if (commonPrivate) { delete commonPrivate; embed->data = NULL; } } GtkWidget * gtk_moz_embed_common_new(void) { GtkWidget *widget = (GtkWidget*) gtk_type_new(gtk_moz_embed_common_get_type()); gtk_widget_set_name(widget, "gtkmozembedcommon"); return (GtkWidget *) widget; } gboolean gtk_moz_embed_common_set_pref(GtkType type, gchar *name, gpointer value) { g_return_val_if_fail (name != NULL, FALSE); nsCOMPtr pref = do_GetService(NS_PREF_CONTRACTID); if (pref) { nsresult rv = NS_ERROR_FAILURE; switch (type) { case GTK_TYPE_BOOL: { /* I doubt this cast pair is correct */ rv = pref->SetBoolPref(name, !!*(int*)value); break; } case GTK_TYPE_INT: { /* I doubt this cast pair is correct */ rv = pref->SetIntPref(name, *(int*)value); break; } case GTK_TYPE_STRING: { g_return_val_if_fail (value, FALSE); rv = pref->SetCharPref(name, (gchar*)value); break; } default: break; } return NS_SUCCEEDED(rv); } return FALSE; } gboolean gtk_moz_embed_common_get_pref(GtkType type, gchar *name, gpointer value) { g_return_val_if_fail (name != NULL, FALSE); nsCOMPtr pref = do_GetService(NS_PREF_CONTRACTID); nsresult rv = NS_ERROR_FAILURE; if (pref){ switch (type) { case GTK_TYPE_BOOL: { rv = pref->GetBoolPref(name, (gboolean*)value); break; } case GTK_TYPE_INT: { rv = pref->GetIntPref(name, (gint*)value); break; } case GTK_TYPE_STRING: { rv = pref->GetCharPref(name, (gchar**)value); break; } default: break; } return NS_SUCCEEDED(rv); } return FALSE; } gboolean gtk_moz_embed_common_save_prefs() { nsCOMPtr prefService = do_GetService(NS_PREF_CONTRACTID); g_return_val_if_fail (prefService != nsnull, FALSE); if (prefService == nsnull) return FALSE; nsresult rv = prefService->SavePrefFile (nsnull); return NS_SUCCEEDED(rv); } gint gtk_moz_embed_common_get_logins(const char* uri, GList **list) { gint ret = 0; #ifdef MOZ_GTKPASSWORD_INTERFACE EmbedPasswordMgr *passwordManager = EmbedPasswordMgr::GetInstance(); nsCOMPtr passwordEnumerator; nsresult result = passwordManager->GetEnumerator(getter_AddRefs(passwordEnumerator)); PRBool enumResult; for (passwordEnumerator->HasMoreElements(&enumResult) ; enumResult == PR_TRUE ; passwordEnumerator->HasMoreElements(&enumResult)) { nsCOMPtr nsPassword; result = passwordEnumerator->GetNext(getter_AddRefs(nsPassword)); if (NS_FAILED(result)) { /* this almost certainly leaks logins */ return ret; } nsCString host; nsPassword->GetHost(host); nsCString nsCURI(uri); if (uri) { if (!StringBeginsWith(nsCURI, host) // && !StringBeginsWith(host, nsCURI) ) continue; } else if (!passwordManager->IsEqualToLastHostQuery(host)) continue; if (list) { nsString unicodeName; nsString unicodePassword; nsPassword->GetUser(unicodeName); nsPassword->GetPassword(unicodePassword); GtkMozLogin * login = g_new0(GtkMozLogin, 1); UNACCEPTABLE_CRASHY_GLIB_ALLOCATION(login); login->user = ToNewUTF8String(unicodeName); ALLOC_NOT_CHECKED(login->user); login->pass = ToNewUTF8String(unicodePassword); ALLOC_NOT_CHECKED(login->pass); login->host = NS_strdup(host.get()); ALLOC_NOT_CHECKED(login->host); login->index = ret; *list = g_list_append(*list, login); } ret++; } #endif return ret; } gboolean gtk_moz_embed_common_remove_passwords(const gchar *host, const gchar *user, gint index) { #ifdef MOZ_GTKPASSWORD_INTERFACE EmbedPasswordMgr *passwordManager = EmbedPasswordMgr::GetInstance(); if (index >= 0) { passwordManager->RemovePasswordsByIndex(index); } else { passwordManager->RemovePasswords(host, user); } #endif return TRUE; } gint gtk_moz_embed_common_get_history_list(GtkMozHistoryItem **GtkHI) { gint count = 0; EmbedGlobalHistory *history = EmbedGlobalHistory::GetInstance(); history->GetContentList(GtkHI, &count); return count; } gint gtk_moz_embed_common_remove_history(gchar *url, gint time) { nsresult rv; // The global history service nsCOMPtr globalHistory(do_GetService("@mozilla.org/browser/global-history;2")); if (!globalHistory) return NS_ERROR_NULL_POINTER; // The browser history interface nsCOMPtr myHistory = do_QueryInterface(globalHistory, &rv); if (!myHistory) return NS_ERROR_NULL_POINTER ; if (!url) myHistory->Observe(nsnull, "RemoveEntries", nsnull); else { EmbedGlobalHistory *history = EmbedGlobalHistory::GetInstance(); PRUnichar *uniurl = ToNewUnicode(NS_ConvertUTF8toUTF16(url)); rv = history->RemoveEntries(uniurl, time); NS_Free(uniurl); } return 1; } GSList* gtk_moz_embed_common_get_cookie_list(void) { GSList *cookies = NULL; nsresult result; nsCOMPtr cookieManager = do_GetService(NS_COOKIEMANAGER_CONTRACTID); nsCOMPtr cookieEnumerator; result = cookieManager->GetEnumerator(getter_AddRefs(cookieEnumerator)); g_return_val_if_fail(NS_SUCCEEDED(result), NULL); PRBool enumResult; for (cookieEnumerator->HasMoreElements(&enumResult); enumResult == PR_TRUE; cookieEnumerator->HasMoreElements(&enumResult)) { GtkMozCookieList *c; nsCOMPtr nsCookie; result = cookieEnumerator->GetNext(getter_AddRefs(nsCookie)); g_return_val_if_fail(NS_SUCCEEDED(result), NULL); c = g_new0(GtkMozCookieList, 1); UNACCEPTABLE_CRASHY_GLIB_ALLOCATION(c); nsCAutoString transfer; nsCookie->GetHost(transfer); c->domain = g_strdup(transfer.get()); nsCookie->GetName(transfer); c->name = g_strdup(transfer.get()); nsCookie->GetValue(transfer); c->value = g_strdup(transfer.get()); nsCookie->GetPath(transfer); /* this almost certainly leaks g_strconcat */ if (strchr(c->domain,'.')) c->path = g_strdup(g_strconcat("http://*",c->domain,"/",NULL)); else c->path = g_strdup(g_strconcat("http://",c->domain,"/",NULL)); cookies = g_slist_prepend(cookies, c); } cookies = g_slist_reverse(cookies); return cookies; } gint gtk_moz_embed_common_delete_all_cookies(GSList *deletedCookies) { nsCOMPtr permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); if (!permissionManager) return 1; permissionManager->RemoveAll(); if (!deletedCookies) return 1; nsCOMPtr cookieManager = do_GetService(NS_COOKIEMANAGER_CONTRACTID); if (!cookieManager) return 1; cookieManager->RemoveAll(); g_slist_free(deletedCookies); return 0;//False in GWebStatus means OK, as opposed to gboolean in C } unsigned char * gtk_moz_embed_common_nsx509_to_raw(void *nsIX509Ptr, guint *len) { if (!nsIX509Ptr) return NULL; unsigned char *data; ((nsIX509Cert*)nsIX509Ptr)->GetRawDER(len, (PRUint8 **)&data); if (!data) return NULL; return data; } gint gtk_moz_embed_common_get_plugins_list(GList **pluginArray) { nsresult rv; nsCOMPtr pluginMan = do_GetService(kPluginManagerCID, &rv); if (NS_FAILED(rv)) { g_print("Could not get the plugin manager\n"); return -1; } pluginMan->ReloadPlugins(PR_TRUE); //FIXME XXX MEMLEAK nsCOMPtr pluginHost = do_GetService(kPluginManagerCID, &rv); if (NS_FAILED(rv)) return -1; PRUint32 aLength; pluginHost->GetPluginCount(&aLength); if (!pluginArray) return (gint)aLength; nsIDOMPlugin **aItems = nsnull; aItems = new nsIDOMPlugin*[aLength]; if (!aItems) return -1; //NO MEMORY rv = pluginHost->GetPlugins(aLength, aItems); if (NS_FAILED(rv)) { delete [] aItems; return -1; } nsString string; for (int plugin_index = 0; plugin_index < (gint) aLength; plugin_index++) { GtkMozPlugin *list_item = g_new0(GtkMozPlugin, 1); UNACCEPTABLE_CRASHY_GLIB_ALLOCATION(list_item); rv = aItems[plugin_index]->GetName(string); if (!NS_FAILED(rv)) list_item->title = g_strdup(NS_ConvertUTF16toUTF8(string).get()); aItems[plugin_index]->GetFilename(string); if (!NS_FAILED(rv)) list_item->path = g_strdup(NS_ConvertUTF16toUTF8(string).get()); nsCOMPtr mimeType; PRUint32 mime_count = 0; rv = aItems[plugin_index]->GetLength(&mime_count); if (NS_FAILED(rv)) continue; nsString single_mime; string.SetLength(0); for (int mime_index = 0; mime_index < mime_count; ++mime_index) { rv = aItems[plugin_index]->Item(mime_index, getter_AddRefs(mimeType)); if (NS_FAILED(rv)) continue; rv = mimeType->GetDescription(single_mime); if (!NS_FAILED(rv)) { string.Append(single_mime); string.AppendLiteral(";"); } } list_item->type = g_strdup(NS_ConvertUTF16toUTF8(string).get()); if (!NS_FAILED(rv)) *pluginArray = g_list_append(*pluginArray, list_item); } delete [] aItems; return (gint)aLength; } void gtk_moz_embed_common_reload_plugins() { nsresult rv; nsCOMPtr pluginMan = do_GetService(kPluginManagerCID, &rv); pluginMan->ReloadPlugins(PR_TRUE); //FIXME XXX MEMLEAK } guint gtk_moz_embed_common_get_security_mode(guint sec_state) { GtkMozEmbedSecurityMode sec_mode; const guint wpl_security_bits = nsIWebProgressListener::STATE_IS_SECURE | nsIWebProgressListener::STATE_IS_BROKEN | nsIWebProgressListener::STATE_IS_INSECURE | nsIWebProgressListener::STATE_SECURE_HIGH | nsIWebProgressListener::STATE_SECURE_MED | nsIWebProgressListener::STATE_SECURE_LOW; /* sec_state is defined as a bitmask that may be extended in the future. * We filter out any unknown bits before testing for known values. */ switch (sec_state & wpl_security_bits) { case nsIWebProgressListener::STATE_IS_INSECURE: sec_mode = GTK_MOZ_EMBED_NO_SECURITY; //g_print("GTK_MOZ_EMBED_NO_SECURITY\n"); break; case nsIWebProgressListener::STATE_IS_BROKEN: sec_mode = GTK_MOZ_EMBED_NO_SECURITY; //g_print("GTK_MOZ_EMBED_NO_SECURITY\n"); break; case nsIWebProgressListener::STATE_IS_SECURE| nsIWebProgressListener::STATE_SECURE_HIGH: sec_mode = GTK_MOZ_EMBED_HIGH_SECURITY; //g_print("GTK_MOZ_EMBED_HIGH_SECURITY"); break; case nsIWebProgressListener::STATE_IS_SECURE| nsIWebProgressListener::STATE_SECURE_MED: sec_mode = GTK_MOZ_EMBED_MEDIUM_SECURITY; //g_print("GTK_MOZ_EMBED_MEDIUM_SECURITY\n"); break; case nsIWebProgressListener::STATE_IS_SECURE| nsIWebProgressListener::STATE_SECURE_LOW: sec_mode = GTK_MOZ_EMBED_LOW_SECURITY; //g_print("GTK_MOZ_EMBED_LOW_SECURITY\n"); break; default: sec_mode = GTK_MOZ_EMBED_UNKNOWN_SECURITY; //g_print("GTK_MOZ_EMBED_UNKNOWN_SECURITY\n"); break; } return sec_mode; } gint gtk_moz_embed_common_clear_cache(void) { nsCacheStoragePolicy storagePolicy; nsCOMPtr cacheService = do_GetService(NS_CACHESERVICE_CONTRACTID); if (cacheService) { //clean disk cache and memory cache storagePolicy = nsICache::STORE_ANYWHERE; cacheService->EvictEntries(storagePolicy); return 0; } return 1; } gboolean gtk_moz_embed_common_observe(const gchar* service_id, gpointer object, const gchar* topic, gunichar* data) { nsresult rv; if (service_id) { nsCOMPtr service = do_GetService(service_id, &rv); NS_ENSURE_SUCCESS(rv, FALSE); nsCOMPtr Observer = do_QueryInterface(service, &rv); NS_ENSURE_SUCCESS(rv, FALSE); rv = Observer->Observe((nsISupports*)object, topic, (PRUnichar*)data); } else { //This is the correct? nsCOMPtr obsService = do_GetService("@mozilla.org/observer-service;1", &rv); if (obsService) rv = obsService->NotifyObservers((nsISupports*)object, topic, (PRUnichar*)data); } return NS_FAILED(rv) ? FALSE : TRUE; }