Initial import of ephy (rev# 7126) from svn
[ephy-soc.git] / embed / mozilla / .svn / text-base / EphyHeaderSniffer.cpp.svn-base
blob66c19a8a50acd8aa2f775833e73cdfa04647149a
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is Chimera code.
15  *
16  * The Initial Developer of the Original Code is
17  * Netscape Communications Corporation.
18  * Portions created by the Initial Developer are Copyright © 2002
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  *   David Hyatt  <hyatt@netscape.com>
23  *   Simon Fraser <sfraser@netscape.com>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK *****
38  *
39  * $Id$
40  */
42 #include "mozilla-config.h"
43 #include "config.h"
45 #include <glib/gi18n.h>
46 #include <libgnomevfs/gnome-vfs-utils.h>
48 #include <nsStringAPI.h>
50 #include <nsComponentManagerUtils.h>
51 #include <nsIChannel.h>
52 #include <nsIDOMDocument.h>
53 #include <nsIDOMHTMLDocument.h>
54 #include <nsIDownload.h>
55 #include <nsIHttpChannel.h>
56 #include <nsIInputStream.h>
57 #include <nsILocalFile.h>
58 #include <nsIMIMEHeaderParam.h>
59 #include <nsIMIMEInfo.h>
60 #include <nsIMIMEService.h>
61 #include <nsIPrefService.h>
62 #include <nsIPromptService.h>
63 #include <nsIURI.h>
64 #include <nsIURL.h>
65 #include <nsIWebBrowserPersist.h>
66 #include <nsIWindowWatcher.h>
67 #include <nsServiceManagerUtils.h>
68 #include <nsXPCOMCID.h>
70 #include "eel-gconf-extensions.h"
71 #include "ephy-debug.h"
72 #include "ephy-file-chooser.h"
73 #include "ephy-gui.h"
74 #include "ephy-prefs.h"
76 #include "EphyBadCertRejector.h"
77 #include "MozDownload.h"
79 #include "EphyHeaderSniffer.h"
81 EphyHeaderSniffer::EphyHeaderSniffer (nsIWebBrowserPersist* aPersist, MozillaEmbedPersist *aEmbedPersist,
82                 nsIFile* aFile, nsIURI* aURL, nsIDOMDocument* aDocument, nsIInputStream* aPostData,
83                 EphyEmbedSingle *single)
84 : mPersist(aPersist)
85 , mEmbedPersist(aEmbedPersist)
86 , mTmpFile(aFile)
87 , mURL(aURL)
88 , mOriginalURI(nsnull)
89 , mDocument(aDocument)
90 , mPostData(aPostData)
92         LOG ("EphyHeaderSniffer ctor (%p)", this);
94         nsCOMPtr<nsIWindowWatcher> watcher
95                 (do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
96         if (!watcher) return;
98         watcher->GetNewAuthPrompter (nsnull, getter_AddRefs (mAuthPrompt));
100         mSingle = single;
101         g_object_add_weak_pointer (G_OBJECT (mSingle),
102                                    (gpointer *)&mSingle);
105 EphyHeaderSniffer::~EphyHeaderSniffer()
107         LOG ("EphyHeaderSniffer dtor (%p)", this);
109         if (mSingle)
110         {
111                 g_object_remove_weak_pointer (G_OBJECT (mSingle),
112                                               (gpointer *)&mSingle);
113         }
116 NS_IMPL_ISUPPORTS3 (EphyHeaderSniffer,
117                     nsIWebProgressListener,
118                     nsIInterfaceRequestor,
119                     nsIAuthPrompt)
121 NS_IMETHODIMP
122 EphyHeaderSniffer::HandleContent ()
124         gboolean handled = FALSE;
125         nsCString uriSpec;
127         if (mPostData || !mSingle) return NS_ERROR_FAILURE;
129         mURL->GetSpec (uriSpec);
130         
131         g_signal_emit_by_name (mSingle, "handle_content", mContentType.get(),
132                                uriSpec.get(), &handled);
134         return handled ? NS_OK : NS_ERROR_FAILURE;
137 NS_IMETHODIMP 
138 EphyHeaderSniffer::OnStateChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, 
139                                   PRUint32 aStatus)
140 {  
141         if (aStateFlags & nsIWebProgressListener::STATE_START)
142         {
143                 /* be sure to keep it alive while we save since it owns
144                    us as a listener and keep ourselves alive */
145                 nsCOMPtr<nsIWebBrowserPersist> kungFuDeathGrip(mPersist);
146                 nsCOMPtr<nsIWebProgressListener> kungFuSuicideGrip(this);
147     
148                 nsresult rv;
149                 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest, &rv);
150                 if (!channel) return rv;
151                 channel->GetContentType(mContentType);
152     
153                 nsCOMPtr<nsIURI> origURI;
154                 channel->GetOriginalURI(getter_AddRefs(origURI));
155     
156                 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
157                 if (httpChannel)
158                 {
159                         httpChannel->GetResponseHeader(nsCString("content-disposition"),
160                                                        mContentDisposition);
161                 }
162     
163                 mPersist->CancelSave();
165                 PRBool exists;
166                 mTmpFile->Exists(&exists);
167                 if (exists)
168                 {
169                         mTmpFile->Remove(PR_FALSE);
170                 }
172                 rv = HandleContent ();
173                 if (NS_SUCCEEDED (rv)) return NS_OK;
175                 rv = PerformSave(origURI);
176                 if (NS_FAILED(rv))
177                 {
178                         /* FIXME put up some UI */
179       
180                 }
181         }
183         return NS_OK;
186 NS_IMETHODIMP 
187 EphyHeaderSniffer::OnProgressChange (nsIWebProgress *aWebProgress, 
188                                      nsIRequest *aRequest, 
189                                      PRInt32 aCurSelfProgress, 
190                                      PRInt32 aMaxSelfProgress, 
191                                      PRInt32 aCurTotalProgress, 
192                                      PRInt32 aMaxTotalProgress)
194         return NS_OK;
197 NS_IMETHODIMP 
198 EphyHeaderSniffer::OnLocationChange (nsIWebProgress *aWebProgress, 
199                                      nsIRequest *aRequest, 
200                                      nsIURI *location)
202         return NS_OK;
205 NS_IMETHODIMP 
206 EphyHeaderSniffer::OnStatusChange (nsIWebProgress *aWebProgress, 
207                                    nsIRequest *aRequest, 
208                                    nsresult aStatus, 
209                                    const PRUnichar *aMessage)
211         return NS_OK;
214 NS_IMETHODIMP 
215 EphyHeaderSniffer::OnSecurityChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
217         return NS_OK;
220 /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
221 NS_IMETHODIMP
222 EphyHeaderSniffer::GetInterface(const nsIID & uuid, void * *result)
224         if (uuid.Equals (NS_GET_IID (nsIBadCertListener)) &&
225             mEmbedPersist)
226         {
227                 EphyEmbedPersistFlags flags;
229                 g_object_get (mEmbedPersist, "flags", &flags, (char *) NULL);
231                 if (flags & EPHY_EMBED_PERSIST_NO_CERTDIALOGS)
232                 {
233                         EphyBadCertRejector *badCertRejector = new EphyBadCertRejector ();
234                         if (!badCertRejector) return NS_ERROR_OUT_OF_MEMORY;
236                         *result = NS_STATIC_CAST(nsIBadCertListener*, badCertRejector);
237                         NS_ADDREF (badCertRejector);
239                         return NS_OK;
240                 }
241         }
243         return NS_ERROR_NO_INTERFACE;
246 static void
247 filechooser_response_cb (GtkWidget *dialog,
248                          gint response, 
249                          EphyHeaderSniffer* sniffer)
251         if (response == GTK_RESPONSE_ACCEPT)
252         {
253                 char *filename;
255                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
257                 if (ephy_gui_check_location_writable (dialog, filename) == FALSE)
258                 {
259                         g_free (filename);
260                         return;
261                 }
263                 nsCOMPtr<nsILocalFile> destFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
264                 if (destFile)
265                 {
266                         destFile->InitWithNativePath (nsCString (filename));
268                         sniffer->InitiateDownload (destFile);
269                 }
271                 g_free (filename);
272         }
274         // FIXME how to inform user of failed save ?
276         gtk_widget_destroy (GTK_WIDGET (dialog));
279 nsresult EphyHeaderSniffer::PerformSave (nsIURI* inOriginalURI)
281         nsresult rv;
282         EphyEmbedPersistFlags flags;
283         PRBool askDownloadDest;
285         mOriginalURI = inOriginalURI;
287         flags = ephy_embed_persist_get_flags (EPHY_EMBED_PERSIST (mEmbedPersist));
288         askDownloadDest = flags & EPHY_EMBED_PERSIST_ASK_DESTINATION;
290         nsString defaultFileName;
292         if (!defaultFileName.Length() && mContentDisposition.Length())
293         {
294                 /* 1 Use the HTTP header suggestion. */
295                 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
296                         do_GetService("@mozilla.org/network/mime-hdrparam;1");     
297                 
298                 if (mimehdrpar)
299                 {
300                         nsCString fallbackCharset;
301                         if (mURL)
302                         {
303                                 mURL->GetOriginCharset(fallbackCharset);
304                         }
305                         
306                         nsString fileName;
307                         
308                         rv = mimehdrpar->GetParameter (mContentDisposition, "filename",
309                                                        fallbackCharset, PR_TRUE, nsnull,
310                                                        fileName);
311                         if (NS_FAILED(rv) || !fileName.Length())
312                         {
313                                 rv = mimehdrpar->GetParameter (mContentDisposition, "name",
314                                                                fallbackCharset, PR_TRUE, nsnull,
315                                                                fileName);
316                         }
318                         if (NS_SUCCEEDED(rv) && fileName.Length())
319                         {
320                                 defaultFileName = fileName;
321                         }
322                 }
323         }
324     
325         if (!defaultFileName.Length())
326         {
327                 /* 2 For file URLs, use the file name. */
329                 nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
330                 if (url)
331                 {
332                         nsCString fileNameCString;
333                         url->GetFileName(fileNameCString);
334                         NS_CStringToUTF16 (fileNameCString, NS_CSTRING_ENCODING_UTF8,
335                                            defaultFileName);
336                 }
337         }
338     
339         if (!defaultFileName.Length() && mDocument)
340         {
341                 /* 3 Use the title of the document. */
343                 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
344                 if (htmlDoc)
345                 {
346                         htmlDoc->GetTitle(defaultFileName);
347                 }
348         }
349     
350         if (!defaultFileName.Length() && mURL)
351         {
352                 /* 4 Use the host. */
353                 nsCString hostName;
354                 mURL->GetHost(hostName);
355                 NS_CStringToUTF16 (hostName, NS_CSTRING_ENCODING_UTF8,
356                                    defaultFileName);
357         }
358     
359         /* 5 One last case to handle about:blank and other untitled pages. */
360         if (!defaultFileName.Length())
361         {
362                 NS_CStringToUTF16 (nsCString(_("Untitled")),
363                                    NS_CSTRING_ENCODING_UTF8, defaultFileName);
364         }
365         
366         /* Validate the file name to ensure legality. */
367         nsCString cDefaultFileName;
368         NS_UTF16ToCString (defaultFileName, NS_CSTRING_ENCODING_UTF8,
369                            cDefaultFileName);
370         char *default_name = g_strdup (cDefaultFileName.get());
371         default_name = g_strdelimit (default_name, "/\\:", ' ');
373         const char *key;
374         key = ephy_embed_persist_get_persist_key (EPHY_EMBED_PERSIST (mEmbedPersist));
376         /* FIXME: do better here by using nsITextToSubURI service, like in
377          * http://lxr.mozilla.org/seamonkey/source/xpfe/communicator/resources/content/contentAreaUtils.js#763
378          */
379         char *filename;
380         filename = gnome_vfs_unescape_string (default_name, NULL);
382         if (!g_utf8_validate (filename, -1, NULL))
383         {
384                 g_free (filename);
385                 filename = g_strdup (default_name);
386         }
388         g_free (default_name);
390         if (askDownloadDest)
391         {
392                 EphyFileChooser *dialog;
393                 GtkWindow *window;
394                 const char *title;
395                 guint32 user_time;
397                 title = ephy_embed_persist_get_fc_title (EPHY_EMBED_PERSIST (mEmbedPersist));
398                 window = ephy_embed_persist_get_fc_parent (EPHY_EMBED_PERSIST (mEmbedPersist));
400                 user_time = ephy_embed_persist_get_user_time (EPHY_EMBED_PERSIST (mEmbedPersist));
401                 if (user_time == 0)
402                 {
403                         g_warning ("EphyHeaderSniffer::PerformSave without valid user time!\n");
404                 }
406                 dialog = ephy_file_chooser_new (title ? title: _("Save"),
407                                                 GTK_WIDGET (window),
408                                                 GTK_FILE_CHOOSER_ACTION_SAVE,
409                                                 key ? key : CONF_STATE_SAVE_DIR,
410                                                 EPHY_FILE_FILTER_ALL_SUPPORTED);
411                 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
413                 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog),
414                                                    filename);
416                 g_signal_connect (dialog, "response",
417                                   G_CALLBACK (filechooser_response_cb), this);
419                 ephy_gui_window_update_user_time (GTK_WIDGET (dialog), user_time);
420                 gtk_widget_show (GTK_WIDGET (dialog));
422                 g_free (filename);
423                 return NS_OK;
424         }
425         /* FIXME: how to inform user of failed save ? */
427         nsCOMPtr<nsILocalFile> destFile;
428         BuildDownloadPath (filename, getter_AddRefs (destFile));
429         g_free (filename);
430         NS_ENSURE_TRUE (destFile, NS_ERROR_FAILURE);
432         return InitiateDownload (destFile);
435 nsresult EphyHeaderSniffer::InitiateDownload (nsILocalFile *aDestFile)
437         LOG ("Initiating download");
439         return InitiateMozillaDownload (mDocument, mURL, aDestFile,
440                                         mContentType.get(), mOriginalURI, mEmbedPersist,
441                                         mPostData, nsnull, -1);