sugar-toolkit-gtk3/browser/GeckoBrowserPersist.cpp

184 lines
5.6 KiB
C++

#include <config.h>
#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 "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)
{
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;
}
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;
}