diff options
Diffstat (limited to 'browser/GeckoBrowserPersist.cpp')
-rw-r--r-- | browser/GeckoBrowserPersist.cpp | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/browser/GeckoBrowserPersist.cpp b/browser/GeckoBrowserPersist.cpp new file mode 100644 index 0000000..48de4d1 --- /dev/null +++ b/browser/GeckoBrowserPersist.cpp @@ -0,0 +1,185 @@ +#include <stdio.h> + +#include <gtkmozembed.h> +#include <gtkmozembed_internal.h> +#include <nsIRequest.h> +#include <nsNetUtil.h> +#include <nsISeekableStream.h> +#include <nsIHttpChannel.h> +#include <nsIUploadChannel.h> +#include <nsIWebBrowser.h> +#include <nsISHistory.h> +#include <nsIHistoryEntry.h> +#include <nsISHEntry.h> +#include <nsIInputStream.h> +#include <nsIWebNavigation.h> + +#include <config.h> +#include "GeckoBrowserPersist.h" + +GeckoBrowserPersist::GeckoBrowserPersist(SugarBrowser *browser) + : mBrowser(browser) +{ +} + +GeckoBrowserPersist::~GeckoBrowserPersist() +{ +} + +static nsresult +NewURI(const char *uri, nsIURI **result) +{ + nsresult rv; + + nsCOMPtr<nsIServiceManager> mgr; + NS_GetServiceManager (getter_AddRefs (mgr)); + NS_ENSURE_TRUE(mgr, FALSE); + + nsCOMPtr<nsIIOService> ioService; + rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1", + NS_GET_IID (nsIIOService), + getter_AddRefs(ioService)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCString cSpec(uri); + return ioService->NewURI (cSpec, nsnull, nsnull, result); +} + +static nsresult +GetPostData(SugarBrowser *browser, nsIInputStream **postData) +{ +#ifdef HAVE_NS_WEB_BROWSER + nsCOMPtr<nsIWebBrowser> webBrowser; + gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), + getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser)); + NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); + + PRInt32 sindex; + + nsCOMPtr<nsISHistory> sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE); + + nsCOMPtr<nsIHistoryEntry> entry; + sessionHistory->GetIndex(&sindex); + sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry)); + + nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(entry)); + if (shEntry) { + shEntry->GetPostData(postData); + } + + return NS_OK; +#endif + return NS_ERROR_NOT_IMPLEMENTED; +} + +bool +GeckoBrowserPersist::SaveURI(const char *uri, const char *filename) +{ + nsresult rv; + + nsCOMPtr<nsIURI> sourceURI; + rv = NewURI(uri, getter_AddRefs(sourceURI)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCOMPtr<nsILocalFile> destFile = do_CreateInstance("@mozilla.org/file/local;1"); + NS_ENSURE_TRUE(destFile, FALSE); + + destFile->InitWithNativePath(nsCString(filename)); + + nsCOMPtr<nsIInputStream> postData; + GetPostData(mBrowser, getter_AddRefs(postData)); + + nsCOMPtr<nsIChannel> inputChannel; + rv = NS_NewChannel(getter_AddRefs(inputChannel), sourceURI, + nsnull, nsnull, nsnull, nsIRequest::LOAD_NORMAL); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel)); + if (httpChannel) { + nsCOMPtr<nsISeekableStream> stream(do_QueryInterface(postData)); + if (stream) + { + // Rewind the postdata stream + stream->Seek(nsISeekableStream::NS_SEEK_SET, 0); + nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel)); + NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel"); + // Attach the postdata to the http channel + uploadChannel->SetUploadStream(postData, EmptyCString(), -1); + } + } + + nsCOMPtr<nsIInputStream> stream; + rv = inputChannel->Open(getter_AddRefs(stream)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCOMPtr<nsIFileOutputStream> fileOutputStream = + do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, FALSE); + + rv = fileOutputStream->Init(destFile, -1, -1, 0); + NS_ENSURE_SUCCESS(rv, FALSE); + + // Read data from the input and write to the output + char buffer[8192]; + PRUint32 bytesRead; + PRUint32 bytesRemaining; + PRBool cancel = PR_FALSE; + PRBool readError; + + rv = stream->Available(&bytesRemaining); + NS_ENSURE_SUCCESS(rv, FALSE); + + while (!cancel && bytesRemaining) + { + readError = PR_TRUE; + rv = stream->Read(buffer, PR_MIN(sizeof(buffer), bytesRemaining), &bytesRead); + if (NS_SUCCEEDED(rv)) + { + readError = PR_FALSE; + // Write out the data until something goes wrong, or, it is + // all written. We loop because for some errors (e.g., disk + // full), we get NS_OK with some bytes written, then an error. + // So, we want to write again in that case to get the actual + // error code. + const char *bufPtr = buffer; // Where to write from. + while (NS_SUCCEEDED(rv) && bytesRead) + { + PRUint32 bytesWritten = 0; + rv = fileOutputStream->Write(bufPtr, bytesRead, &bytesWritten); + if (NS_SUCCEEDED(rv)) + { + bytesRead -= bytesWritten; + bufPtr += bytesWritten; + bytesRemaining -= bytesWritten; + // Force an error if (for some reason) we get NS_OK but + // no bytes written. + if (!bytesWritten) + { + rv = NS_ERROR_FAILURE; + cancel = PR_TRUE; + } + } + else + { + // Disaster - can't write out the bytes - disk full / permission? + cancel = PR_TRUE; + } + } + } + else + { + // Disaster - can't read the bytes - broken link / file error? + cancel = PR_TRUE; + } + } + NS_ENSURE_SUCCESS(rv, FALSE); + + stream->Close(); + + return TRUE; +} |