#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "GeckoBrowserPersist.h" GeckoBrowserPersist::GeckoBrowserPersist(SugarBrowser *browser) : mBrowser(browser) { } GeckoBrowserPersist::~GeckoBrowserPersist() { } static nsresult NewURI(const char *uri, nsIURI **result) { nsresult rv; nsCOMPtr mgr; NS_GetServiceManager (getter_AddRefs (mgr)); NS_ENSURE_TRUE(mgr, FALSE); nsCOMPtr 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 webBrowser; gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), getter_AddRefs(webBrowser)); NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE); nsCOMPtr webNav(do_QueryInterface(webBrowser)); NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); PRInt32 sindex; nsCOMPtr sessionHistory; webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE); nsCOMPtr entry; sessionHistory->GetIndex(&sindex); sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry)); nsCOMPtr shEntry(do_QueryInterface(entry)); if (shEntry) { shEntry->GetPostData(postData); } return NS_OK; } bool GeckoBrowserPersist::SaveURI(const char *uri, const char *filename) { nsresult rv; nsCOMPtr sourceURI; rv = NewURI(uri, getter_AddRefs(sourceURI)); NS_ENSURE_SUCCESS(rv, FALSE); nsCOMPtr destFile = do_CreateInstance("@mozilla.org/file/local;1"); NS_ENSURE_TRUE(destFile, FALSE); destFile->InitWithNativePath(nsCString(filename)); nsCOMPtr postData; GetPostData(mBrowser, getter_AddRefs(postData)); nsCOMPtr inputChannel; rv = NS_NewChannel(getter_AddRefs(inputChannel), sourceURI, nsnull, nsnull, nsnull, nsIRequest::LOAD_NORMAL); NS_ENSURE_SUCCESS(rv, FALSE); nsCOMPtr httpChannel(do_QueryInterface(inputChannel)); if (httpChannel) { nsCOMPtr stream(do_QueryInterface(postData)); if (stream) { // Rewind the postdata stream stream->Seek(nsISeekableStream::NS_SEEK_SET, 0); nsCOMPtr uploadChannel(do_QueryInterface(httpChannel)); NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel"); // Attach the postdata to the http channel uploadChannel->SetUploadStream(postData, EmptyCString(), -1); } } nsCOMPtr stream; rv = inputChannel->Open(getter_AddRefs(stream)); NS_ENSURE_SUCCESS(rv, FALSE); nsCOMPtr 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; }