You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

442 lines
13 KiB

#include "stdafx.h"
#include "SaveAsHandler.h"
#include "Utils.h"
#include "MozUtils.h"
#include "MfcEmbed.h"
extern CMfcEmbedApp theApp;
#include "nsIMIMEHeaderParam.h"
#include "nsIMIMEService.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIStandardURL.h"
#include "nsIURL.h"
#include "nsIDOMHTMLDocument.h"
#include "UnknownContentTypeHandler.h"
#include "nsCWebBrowserPersist.h"
#include "nsIMIMEInfo.h"
NS_IMPL_ISUPPORTS(CSaveAsHandler, nsIWebProgressListener);
CSaveAsHandler::CSaveAsHandler(
nsIWebBrowserPersist* aPersist,
nsIURI* aURL, nsIDOMDocument* aDocument,
nsISupports* aDescriptor, nsIURI* aReferrer)
{
mPersist = aPersist;
mDescriptor = aDescriptor;
mURL = aURL;
mFile = nullptr;
mDocument = aDocument;
mReferrer = aReferrer;
}
CSaveAsHandler::~CSaveAsHandler() {}
NS_IMETHODIMP CSaveAsHandler::OnStateChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRUint32 aStateFlags,
nsresult aStatus)
{
nsresult rv = NS_OK;
if (aStateFlags & nsIWebProgressListener::STATE_START)
{
nsCOMPtr<nsIWebProgressListener> KeepAlive(this);
nsCString sContentType;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest, &rv);
if (!channel) return rv;
channel->GetContentType(sContentType);
channel->GetURI(getter_AddRefs(mRealURI));
nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(channel));
if (httpchannel) {
bool b;
rv = httpchannel->GetRequestSucceeded(&b);
// If we get an error, remove the content type since it's html and
// the download will fail
if (NS_SUCCEEDED(rv) && b == PR_FALSE) {
sContentType.SetLength(0);
}
httpchannel->GetResponseHeader(nsCString("content-disposition"), mContentDisposition);
}
mPersist->CancelSave();
if (mFile) mFile->Remove(PR_FALSE);
// Defering the save as dialog to not stall other transferts
::AfxGetApp()->m_pMainWnd->PostMessage(WM_DEFERSAVEAS, (WPARAM)this, (LPARAM)strdup(sContentType.get()));
NS_ADDREF_THIS();
//rv = Save(sContentType.get());
}
return rv;
}
NS_IMETHODIMP CSaveAsHandler::Save(const char* contentType, const char* disposition)
{
NS_ENSURE_ARG(contentType);
NS_ENSURE_ARG(mURL || mRealURI);
if (!mRealURI) mRealURI = mURL;
mContentType = contentType;
if (disposition && *disposition)
mContentDisposition.Assign(disposition);
nsresult rv;
nsString fileName;
PRBool isHTML =
(strcmp(contentType, "text/html") == 0) ||
(strcmp(contentType, "text/xml") == 0) ||
(strcmp(contentType, "application/xhtml+xml") == 0) ;
if (mContentDisposition.Length())
{
/* 1 Use the HTTP header suggestion. */
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService("@mozilla.org/network/mime-hdrparam;1");
if (mimehdrpar)
{
nsCString fallbackCharset;
if (mRealURI) mRealURI->GetOriginCharset(fallbackCharset);
rv = mimehdrpar->GetParameter (mContentDisposition,
"filename",
fallbackCharset, PR_TRUE, nullptr,
fileName);
if (NS_FAILED(rv) || !fileName.Length() || wcsicmp(fileName.get(), L"untitled") == 0)
{
rv = mimehdrpar->GetParameter (mContentDisposition, "name",
fallbackCharset, PR_TRUE, nullptr,
fileName);
}
}
}
if ( (!fileName.Length() || wcsicmp(fileName.get(), L"untitled") == 0) && mDocument && isHTML)
{
/* Use the title of the document. */
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
if (htmlDoc) htmlDoc->GetTitle(fileName);
PRUnichar* wc = (PRUnichar*)fileName.get();
for (;*wc;wc++)
if (*wc == L'.') *wc = L'_';
}
if (!fileName.Length() || (mDocument && isHTML && !theApp.preferences.bSaveUseTitle))
{
/* For file URLs, use the file name. */
nsCOMPtr<nsIURL> url(do_QueryInterface(mRealURI));
if (!url)
{
// In some case (wyciwyg) there is no nsIURL, so I'm creating one
nsCOMPtr<nsIStandardURL> test = do_CreateInstance("@mozilla.org/network/standard-url;1");
nsCString spec;
mRealURI->GetSpec(spec);
nsCString charset;
mRealURI->GetOriginCharset(charset);
test->Init(nsIStandardURL::URLTYPE_STANDARD, 80, spec, charset.get(), nullptr);
url = do_QueryInterface(test);
}
if (url)
{
nsCString CfileName;
url->GetFileName(CfileName);
char * ufn = nsUnescape(strdup(CfileName.get()));
CfileName = ufn;
free(ufn);
NS_CStringToUTF16 (CfileName, NS_CSTRING_ENCODING_UTF8, fileName);
//XXX for some reason it may not be in UTF8
if (CfileName.Length() && !fileName.Length())
NS_CStringToUTF16 (CfileName, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, fileName);
}
}
if (!fileName.Length() && mRealURI)
{
/* Use the host. */
nsCString hostName;
mURL->GetHost(hostName);
NS_CStringToUTF16 (hostName, NS_CSTRING_ENCODING_UTF8, fileName);
PRUnichar* wc = (PRUnichar*)fileName.get();
for (;*wc;wc++)
if (*wc == L'.') *wc = L'_';
}
if (!fileName.Length())
fileName = L"Untitled";
CString extension;
CString description;
USES_CONVERSION;
const WCHAR* pExtension = wcsrchr(fileName.get(), L'.');
#ifdef MOZILLA_MIMETYPE_SUCKS
GetFromTypeAndExtension(A2CT(contentType), W2CT(pExtension), extension, description);
if (extension.GetLength())
extension = extension.Mid(1);
#else
nsCOMPtr<nsIMIMEService> MimeService = do_GetService("@mozilla.org/uriloader/external-protocol-service;1");
if (MimeService)
{
nsCOMPtr<nsIMIMEInfo> mimeInfo;
nsCString typeFromExt;
MimeService->GetTypeFromExtension(
pExtension ? nsDependentCString(W2CA(pExtension+1)) : NS_LITERAL_CSTRING(""),
typeFromExt);
// If the extension is unknow our better choice for now is to
// ignore the content type.
//if (typeFromExt.Length())
{
// If both content type and extension are empty the mime type
// editor return windows media file ?????????
if (!strlen(contentType) && !pExtension)
rv = MimeService->GetFromTypeAndExtension(
NS_LITERAL_CSTRING("text/html"),
NS_LITERAL_CSTRING(""),
getter_AddRefs(mimeInfo));
else
rv = MimeService->GetFromTypeAndExtension(
nsDependentCString(contentType),
pExtension ? nsDependentCString(W2CA(pExtension+1)) : NS_LITERAL_CSTRING(""),
getter_AddRefs(mimeInfo));
if (NS_SUCCEEDED(rv) && mimeInfo)
{
//PRBool extMatch = PR_TRUE;
//if (pExtension)
// mimeInfo->ExtensionExists(W2CA(pExtension+1), &extMatch);
//if (extMatch)
//{
nsCString nsCExt;
mimeInfo->GetPrimaryExtension(nsCExt);
nsString nsExt;
NS_CStringToUTF16(nsCExt, NS_CSTRING_ENCODING_UTF8, nsExt);
extension = W2CT(nsExt.get());
nsString nsDesc;
mimeInfo->GetDescription(nsDesc);
description = W2CT(nsDesc.get());
//}
}
}
}
if(extension.IsEmpty() && pExtension)
extension = W2CT(pExtension + 1);
#endif
TCHAR* szFileName = new TCHAR[MAX_PATH+1];
_tcsncpy(szFileName, W2CT(fileName.get()), MAX_PATH-20);
szFileName[MAX_PATH-20] = 0;
MakeFilename(szFileName);
//["@mozilla.org/intl/texttosuburi;1"]
if (theApp.preferences.GetBool("kmeleon.download.useSaveDir", FALSE))
{
CString saveDir = theApp.preferences.GetString("kmeleon.download.saveDir", _T(""));
if (!saveDir.IsEmpty()) {
rv = DownloadTo(CStringToNSString(saveDir + _T('\\') + szFileName + _T('.') + extension),
isHTML, theApp.preferences.iSaveType == 2);
delete [] szFileName;
return rv;
}
}
CString filter;
int defaultSaveType = 1;
if (isHTML && mDocument) {
filter.LoadString(IDS_WEBPAGE_HTMLONLY);
filter += _T(" (*.htm;*.html;*.xhtml)|*.htm;*.html;*.xhtml|");
CString complete;
complete.LoadString(IDS_WEBPAGE_COMPLETE);
filter += complete + _T(" (*.htm;*.html;*.xhtml)|*.htm;*.html;*.xhtml|");
complete.LoadString(IDS_WEBPAGE_TEXT);
filter += complete + _T(" (*.txt)|*.txt|");
defaultSaveType = theApp.preferences.iSaveType;
if (defaultSaveType < 0 || defaultSaveType>3)
defaultSaveType = 2;
}
else
{
if (!description.IsEmpty())
filter = description + _T(" (*.") + extension + _T(")|*.") + extension + _T("|");
else if (!extension.IsEmpty()) {
filter.Format(IDS_UNKNOW_TYPE, extension);
filter+=_T(" (*.") + extension + _T(")|*.") + extension + _T("|");
}
}
CString filt;
filt.LoadString(IDS_ALLFILES);
filter += filt + _T(" (*.*)|*.*||");
rv = NS_ERROR_ABORT;
/* CFileDialog fileDlg(FALSE, extension, MakeFilename(W2T(fileName.get())), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter);
fileDlg.GetOFN().nFilterIndex = (mDocument && isHTML) ? theApp.preferences.iSaveType == 2 ? 2 : 1 : 1;
fileDlg.GetOFN().lpstrInitialDir = theApp.preferences.saveDir;
if (fileDlg.DoModal() == IDOK)
{
CString strFullPath = fileDlg.GetPathName();
fileDlg.Get
*/
TCHAR* lpszFilter = filter.GetBuffer(0);
for (int i=0; lpszFilter[i]; i++)
if (lpszFilter[i] == _T('|'))
lpszFilter[i] = _T('\0');
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFilter = lpszFilter;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
ofn.lpstrInitialDir = theApp.preferences.saveDir;
ofn.lpstrDefExt = extension;
ofn.nFilterIndex = defaultSaveType;
if( ::GetSaveFileName(&ofn) )
{
CString strFullPath = szFileName;
int idxSlash;
idxSlash = strFullPath.ReverseFind(_T('\\'));
theApp.preferences.saveDir = strFullPath.Mid(0, idxSlash+1);
if (isHTML)
theApp.preferences.iSaveType = ofn.nFilterIndex;
rv = DownloadTo(CStringToNSString(strFullPath), isHTML, theApp.preferences.iSaveType);
}
filter.ReleaseBuffer();
delete [] szFileName;
return rv;
}
NS_IMETHODIMP CSaveAsHandler::DownloadTo(nsString& aFilename, BOOL isHTML, int saveType)
{
NS_ENSURE_TRUE(aFilename.Length(), NS_ERROR_FAILURE);
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewLocalFile(aFilename, TRUE, getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv,rv);
// Get the persist interface that we'll use for saving the file
nsCOMPtr<nsIWebBrowserPersist> persist(do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv));
NS_ENSURE_SUCCESS (rv, rv);
if (!mDocument)
{
// Add flag for content conversion (Bug #687)
persist->SetPersistFlags(
nsIWebBrowserPersist::PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION|
nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES);
// Create the progress dialog and initiate the download
CProgressDialog *progress = new CProgressDialog(FALSE);
progress->InitPersist(mRealURI, file, persist, TRUE);
//persist->SetProgressListener(progress);
rv = persist->SaveURI(mRealURI, nullptr, mReferrer, 0, nullptr, nullptr, file, nullptr);
if (NS_FAILED(rv)) { //Remove cycling reference, avoid leaking
persist->SetProgressListener(nullptr);
progress->Close();
}
}
else
{
persist->SetPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES);
if (isHTML)
{
nsCOMPtr<nsIFile> dataFolder;
uint32_t encodingFlags = 0;
if (saveType == 2)
{
// cf.m_ofn.nFilterIndex == 3 indicates
// user want to save the complete document including
// all frames, images, scripts, stylesheets etc.
USES_CONVERSION;
CString strDataPath = W2CT(aFilename.get()), suffix;
suffix.LoadString(IDS_SAVEPAGE_SUFFIX);
int idxPeriod = strDataPath.ReverseFind(_T('.'));
strDataPath = strDataPath.Mid(0, idxPeriod);
strDataPath += suffix;
// At this stage strDataPath will be of the form
// c:\tmp\junk_files - assuming we're saving to a file
// named junk.htm
// Any images etc in the doc will be saved to a dir
// with the name c:\tmp\junk_files
#ifdef _UNICODE
rv = NS_NewLocalFile(nsDependentString(strDataPath), TRUE, getter_AddRefs(dataFolder));
#else
rv = NS_NewNativeLocalFile(nsDependentCString(strDataPath), TRUE, getter_AddRefs(dataFolder));
#endif
NS_ENSURE_SUCCESS(rv,rv);
}
else if (saveType == 3) {
encodingFlags = nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED
|| nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS
|| nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT;
mContentType = "text/plain";
}
rv = persist->SaveDocument(mDocument, file, dataFolder, mContentType.get(), encodingFlags, 0);
}
else
rv = persist->SaveURI(mURL, mDescriptor, mReferrer, 0, nullptr, nullptr, file, nullptr);
}
return rv;
}
NS_IMETHODIMP CSaveAsHandler::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP CSaveAsHandler::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, uint32_t aFlags)
{
return NS_OK;
}
/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP CSaveAsHandler::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
{
return NS_OK;
}
NS_IMETHODIMP CSaveAsHandler::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}