/* * Copyright (C) 2001 Philip Langdale * Copyright (C) 2003 Marco Pesenti Gritti * Copyright (C) 2003 Xan Lopez * Copyright (C) 2004 Christian Persch * * 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. * * $Id$ */ #include "mozilla-config.h" #include "config.h" #include "ContentHandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ALLOW_PRIVATE_API #include #endif #include "ephy-prefs.h" #include "ephy-embed-single.h" #include "ephy-embed-shell.h" #include "ephy-file-chooser.h" #include "ephy-file-helpers.h" #include "ephy-stock-icons.h" #include "ephy-gui.h" #include "ephy-debug.h" #include "eel-gconf-extensions.h" #include "MozDownload.h" #include "EphyUtils.h" /* FIXME: we don't generally have a timestamp for the user action which initiated this * content handler. */ #ifdef HAVE_GECKO_1_8 GContentHandler::GContentHandler() : mUserTime(0) { LOG ("GContentHandler ctor (%p)", this); } #else GContentHandler::GContentHandler() : mMimeType(nsnull) , mUserTime(0) { LOG ("GContentHandler ctor (%p)", this); } #endif GContentHandler::~GContentHandler() { LOG ("GContentHandler dtor (%p)", this); #ifndef HAVE_GECKO_1_8 if (mMimeType) { nsMemory::Free (mMimeType); } #endif } NS_IMPL_ISUPPORTS1(GContentHandler, nsIHelperAppLauncherDialog) #ifdef HAVE_GECKO_1_8 /* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext, in unsigned long aReason); */ NS_IMETHODIMP GContentHandler::Show (nsIHelperAppLauncher *aLauncher, nsISupports *aContext, PRUint32 aReason) #else /* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext); */ NS_IMETHODIMP GContentHandler::Show (nsIHelperAppLauncher *aLauncher, nsISupports *aContext, PRBool aForced) #endif { nsresult rv; EphyEmbedSingle *single; gboolean handled = FALSE; /* FIXME: handle aForced / aReason argument in some way? */ mContext = aContext; mLauncher = aLauncher; rv = Init (); NS_ENSURE_SUCCESS (rv, rv); single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)); #ifdef HAVE_GECKO_1_8 g_signal_emit_by_name (single, "handle_content", mMimeType.get(), mUrl.get(), &handled); #else g_signal_emit_by_name (single, "handle_content", mMimeType, mUrl.get(), &handled); #endif if (!handled) { MIMEInitiateAction (); } else { #ifdef HAVE_GECKO_1_8 mLauncher->Cancel (NS_BINDING_ABORTED); #else mLauncher->Cancel (); #endif } return NS_OK; } /* nsILocalFile promptForSaveToFile (in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */ NS_IMETHODIMP GContentHandler::PromptForSaveToFile( nsIHelperAppLauncher *aLauncher, nsISupports *aWindowContext, const PRUnichar *aDefaultFile, const PRUnichar *aSuggestedFileExtension, nsILocalFile **_retval) { EphyFileChooser *dialog; gint response; char *filename = NULL; nsEmbedCString defaultFile; NS_UTF16ToCString (nsEmbedString (aDefaultFile), NS_CSTRING_ENCODING_UTF8, defaultFile); if (mAction != CONTENT_ACTION_SAVEAS) { return BuildDownloadPath (defaultFile.get(), _retval); } nsCOMPtr parentDOMWindow = do_GetInterface (aWindowContext); GtkWidget *parentWindow = GTK_WIDGET (EphyUtils::FindGtkParent (parentDOMWindow)); dialog = ephy_file_chooser_new (_("Save"), parentWindow, GTK_FILE_CHOOSER_ACTION_SAVE, CONF_STATE_SAVE_DIR, EPHY_FILE_FILTER_ALL); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), defaultFile.get()); if (parentWindow) { gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (parentWindow)), GTK_WINDOW (dialog)); } /* FIXME: this will only be the real user time if we came from ::Show */ ephy_gui_window_update_user_time (GTK_WIDGET (dialog), (guint32) mUserTime); /* FIXME: modal -- mozilla sucks! */ do { g_free (filename); response = gtk_dialog_run (GTK_DIALOG (dialog)); filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); } while (response == GTK_RESPONSE_ACCEPT && !ephy_gui_confirm_overwrite_file (GTK_WIDGET (dialog), filename)); if (response == GTK_RESPONSE_ACCEPT) { nsCOMPtr destFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); NS_ENSURE_TRUE (destFile, NS_ERROR_FAILURE); destFile->InitWithNativePath (nsEmbedCString (filename)); g_free (filename); NS_IF_ADDREF (*_retval = destFile); gtk_widget_destroy (GTK_WIDGET (dialog)); return NS_OK; } else { gtk_widget_destroy (GTK_WIDGET (dialog)); g_free (filename); return NS_ERROR_FAILURE; } } NS_METHOD GContentHandler::Init () { nsresult rv; NS_ENSURE_TRUE (mLauncher, NS_ERROR_FAILURE); nsCOMPtr MIMEInfo; mLauncher->GetMIMEInfo (getter_AddRefs(MIMEInfo)); NS_ENSURE_TRUE (MIMEInfo, NS_ERROR_FAILURE); #ifdef HAVE_GECKO_1_8 rv = MIMEInfo->GetMIMEType (mMimeType); #else rv = MIMEInfo->GetMIMEType (&mMimeType); #endif nsCOMPtr uri; mLauncher->GetSource (getter_AddRefs(uri)); NS_ENSURE_TRUE (uri, NS_ERROR_FAILURE); uri->GetSpec (mUrl); return NS_OK; } static void response_cb (GtkWidget *dialog, int response, GContentHandler *self) { gtk_widget_destroy (dialog); if (response > 0) { self->mAction = (ContentAction) response; } else { self->mAction = CONTENT_ACTION_NONE; } self->MIMEDoAction (); } static void release_cb (GContentHandler *data) { NS_RELEASE (data); } NS_METHOD GContentHandler::MIMEConfirmAction () { GtkWidget *dialog, *button, *image; const char *action_label; nsCOMPtr parentDOMWindow = do_GetInterface (mContext); GtkWindow *parentWindow = GTK_WINDOW (EphyUtils::FindGtkParent(parentDOMWindow)); action_label = (mAction == CONTENT_ACTION_OPEN) || (mAction == CONTENT_ACTION_OPEN_TMP) ? GTK_STOCK_OPEN : EPHY_STOCK_DOWNLOAD; if (mPermission != EPHY_MIME_PERMISSION_SAFE && mHelperApp) { dialog = gtk_message_dialog_new (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, _("Download the unsafe file?")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("This type of file could potentially damage " "your documents or invade your privacy. " "It's not safe to open it directly. " "You can save it instead.")); } else if (mAction == CONTENT_ACTION_OPEN_TMP && mHelperApp) { dialog = gtk_message_dialog_new (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, /* translators: %s is the name of the application */ _("Open this file with \"%s\"?"), mHelperApp->name); gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), /* translators: %s is the name of the application */ _("It's not possible to view this file type " "directly in the browser. You can open it with " "\"%s\" or save it."), mHelperApp->name); } else { dialog = gtk_message_dialog_new (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Download the file?")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("It's not possible to view this file because " "there is no application installed that can open" " it. You can save it instead.")); } button = gtk_button_new_with_label (_("_Save As...")); image = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button), image); gtk_widget_show (image); gtk_widget_show (button); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, CONTENT_ACTION_SAVEAS); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, CONTENT_ACTION_NONE); gtk_dialog_add_button (GTK_DIALOG (dialog), action_label, mAction); gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); gtk_dialog_set_default_response (GTK_DIALOG (dialog), (guint) mAction); NS_ADDREF (this); g_signal_connect_data (dialog, "response", G_CALLBACK (response_cb), this, (GClosureNotify) release_cb, (GConnectFlags) 0); /* FIXME: should find a way to get the user time of the user action which * initiated this content handler */ gtk_window_present (GTK_WINDOW (dialog)); return NS_OK; } NS_METHOD GContentHandler::MIMEInitiateAction (void) { gboolean auto_downloads; if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_SAVE_TO_DISK)) return NS_OK; auto_downloads = eel_gconf_get_boolean (CONF_AUTO_DOWNLOADS); #ifdef HAVE_GECKO_1_8 mHelperApp = gnome_vfs_mime_get_default_application (mMimeType.get()); mPermission = ephy_file_check_mime (mMimeType.get()); #else mHelperApp = gnome_vfs_mime_get_default_application (mMimeType); mPermission = ephy_file_check_mime (mMimeType); #endif if (auto_downloads) { mAction = CONTENT_ACTION_OPEN; } else { mAction = CONTENT_ACTION_OPEN_TMP; } if (!mHelperApp || mPermission != EPHY_MIME_PERMISSION_SAFE) { mAction = CONTENT_ACTION_DOWNLOAD; } if (!auto_downloads || mAction == CONTENT_ACTION_DOWNLOAD) { MIMEConfirmAction (); } else { MIMEDoAction (); } return NS_OK; } NS_METHOD GContentHandler::MIMEDoAction (void) { /* This is okay, since we either clicked on a button, or we get 0 */ mUserTime = gtk_get_current_event_time (); nsCOMPtr mimeInfo; mLauncher->GetMIMEInfo(getter_AddRefs(mimeInfo)); NS_ENSURE_TRUE (mimeInfo, NS_ERROR_FAILURE); if (mAction == CONTENT_ACTION_OPEN) { g_return_val_if_fail (mHelperApp, NS_ERROR_FAILURE); const char *id; id = gnome_vfs_mime_application_get_desktop_id (mHelperApp); /* The current time is fine here as the user has just clicked * a button (it is used as the time for the application opening) */ char *info; info = g_strdup_printf ("gnome-default:%d:%s", gtk_get_current_event_time(), id); nsEmbedString desc; NS_CStringToUTF16 (nsEmbedCString (info), NS_CSTRING_ENCODING_UTF8, desc); g_free (info); /* HACK we use the application description to ask MozDownload to open the file when download is finished */ #ifdef HAVE_GECKO_1_8 mimeInfo->SetApplicationDescription (desc); #else mimeInfo->SetApplicationDescription (desc.get()); #endif } else { #ifdef HAVE_GECKO_1_8 mimeInfo->SetApplicationDescription (nsEmbedString ()); #else mimeInfo->SetApplicationDescription (nsnull); #endif } if (mAction == CONTENT_ACTION_OPEN) { mLauncher->SaveToDisk (nsnull, PR_FALSE); } else if (mAction == CONTENT_ACTION_OPEN_TMP) { mLauncher->LaunchWithApplication (nsnull, PR_FALSE); } else if (mAction == CONTENT_ACTION_NONE) { #ifdef HAVE_GECKO_1_8 mLauncher->Cancel (NS_BINDING_ABORTED); #else mLauncher->Cancel (); #endif } else { mLauncher->SaveToDisk (nsnull, PR_FALSE); } return NS_OK; }