mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
943 lines
26 KiB
C++
Executable File
943 lines
26 KiB
C++
Executable File
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
//
|
|
// OK, so this module is horribly misnamed. It contains all of the external
|
|
// streams defined in the front end
|
|
//
|
|
#include "stdafx.h"
|
|
|
|
#include "display.h"
|
|
|
|
#include "helper.h"
|
|
#include "dialog.h"
|
|
#include "ngdwtrst.h"
|
|
#include "mainfrm.h"
|
|
#include "cxsave.h"
|
|
#include "errno.h"
|
|
#include "prefapi.h"
|
|
#include "extgen.h"
|
|
#include "viewerse.h"
|
|
|
|
extern "C" int MK_DISK_FULL; // defined in allxpstr.h
|
|
extern "C" int MK_OUT_OF_MEMORY; // defined in allxpstr.h
|
|
|
|
/* Stream Object
|
|
** ------------
|
|
*/
|
|
|
|
extern NET_StreamClass *OLE_ViewStream(int format_out, void *pDataObj, URL_Struct *urls,
|
|
MWContext *pContext);
|
|
|
|
|
|
extern char *FE_FindFileExt(char * path);
|
|
extern void FE_LongNameToDosName(char* dest, char* source);
|
|
|
|
#define DEFAULT_BUFFER_SZ 30000
|
|
|
|
struct DataObject {
|
|
/* generic */
|
|
char * address;
|
|
char * format_in;
|
|
MWContext * context;
|
|
int format_out;
|
|
|
|
/* file stuff */
|
|
char * filename;
|
|
FILE * fp;
|
|
|
|
/* memory stuff */
|
|
int32 sz; /* size of buffer */
|
|
char * start; /* start of buffer */
|
|
char * loc; /* current posn in buffer */
|
|
int32 content_length; /* size if known */
|
|
int32 cur_loc;
|
|
|
|
/* external object stuff */
|
|
char * command; /* command to execute */
|
|
char * params;
|
|
int how_handle;
|
|
};
|
|
|
|
|
|
/****************************************************************************
|
|
DISK STREAM DECLARATION
|
|
*****************************************************************************/
|
|
|
|
/* Buffer write.
|
|
** ------------
|
|
*/
|
|
extern "C" int
|
|
disk_stream_write (NET_StreamClass *stream, CONST char* s, int32 len)
|
|
{
|
|
|
|
int32 status;
|
|
|
|
DataObject * data = (DataObject *)stream->data_object;
|
|
|
|
if(!data || !data->fp || !len || !s)
|
|
return(0);
|
|
|
|
status = XP_FileWrite(s, len, data->fp);
|
|
if(len != status) {
|
|
if(errno == ENOSPC)
|
|
return(MK_DISK_FULL);
|
|
else
|
|
return(-1);
|
|
}
|
|
|
|
data->cur_loc += len;
|
|
|
|
float fPercent = 0.0f;
|
|
|
|
if (data->content_length)
|
|
fPercent = (float)data->cur_loc / (float)data->content_length;
|
|
if (data->cur_loc)
|
|
FE_SetProgressBarPercent(data->context, (int)(fPercent * 100));
|
|
|
|
return((int) status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the object
|
|
** ---------------
|
|
**
|
|
*/
|
|
extern "C" void
|
|
disk_stream_complete (NET_StreamClass *stream)
|
|
{
|
|
DataObject * data = (DataObject *)stream->data_object;
|
|
|
|
if(!data)
|
|
return;
|
|
|
|
if(data->fp) {
|
|
fclose(data->fp);
|
|
data->fp = NULL;
|
|
}
|
|
|
|
FE_Progress(data->context, szLoadString(IDS_DOC_LOAD_COMPLETE));
|
|
|
|
if(FEU_Execute(data->context, data->command, data->params)) {
|
|
FE_Progress(data->context, szLoadString(IDS_SPAWNING_EXTERNAL_VIEWER));
|
|
}
|
|
|
|
if(data->address) {
|
|
XP_FREE(data->address);
|
|
data->address = NULL;
|
|
}
|
|
|
|
if(data->filename) {
|
|
XP_FREE(data->filename);
|
|
data->filename = NULL;
|
|
}
|
|
|
|
if(data->params) {
|
|
XP_FREE(data->params);
|
|
data->params = NULL;
|
|
}
|
|
|
|
delete data;
|
|
return;
|
|
}
|
|
|
|
/* End writing
|
|
*/
|
|
|
|
extern "C" void
|
|
disk_stream_abort (NET_StreamClass *stream, int status)
|
|
{
|
|
DataObject * data = (DataObject *)stream->data_object;
|
|
|
|
char * error_string = "<title>Error</title><H1>Error</h1>Unable to load requested item.";
|
|
|
|
if (data->fp)
|
|
XP_FileWrite(error_string, XP_STRLEN(error_string), data->fp);
|
|
|
|
disk_stream_complete(stream);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Always assume we can write no matter what type of stream we are dealing with
|
|
//
|
|
static unsigned int
|
|
write_ready(NET_StreamClass *stream)
|
|
{
|
|
return((unsigned int) MAX_WRITE_READY);
|
|
}
|
|
|
|
static NET_StreamClass *
|
|
ExternalFileSave(int iFormatOut, URL_Struct *pUrl, MWContext *pContext)
|
|
{
|
|
//
|
|
// While we have a pointer to the original frame window query
|
|
// for a filename
|
|
//
|
|
char *pDestination;
|
|
char *pSuggested = NULL;
|
|
NET_StreamClass *pRetval = NULL;
|
|
|
|
// Prompt the user for a file name.
|
|
// Security rist to let path information in externally provided
|
|
// filename (content disposition, filename =)
|
|
if (pUrl->content_name != NULL &&
|
|
strstr(pUrl->content_name, "../") == NULL &&
|
|
strstr(pUrl->content_name, "..\\") == NULL) {
|
|
// Make a copy of the name, because that's what fe_URLtoLocalName() does
|
|
// and the code below is going to XP_FREE pSuggested
|
|
pSuggested = XP_STRDUP(pUrl->content_name);
|
|
if (pSuggested && *pSuggested) {
|
|
// check if the file doesn't have an extension
|
|
char *ext = FE_FindFileExt(pSuggested);
|
|
|
|
if (!ext) {
|
|
if (pUrl->content_type && *pUrl->content_type) {
|
|
// Look up an extension
|
|
char aExt[_MAX_EXT];
|
|
DWORD dwFlags = 0;
|
|
size_t stExt = 0;
|
|
|
|
aExt[0] = '\0';
|
|
#ifdef XP_WIN16
|
|
dwFlags |= EXT_DOT_THREE;
|
|
#endif
|
|
stExt = EXT_Invent(aExt, sizeof(aExt), dwFlags, pSuggested, pUrl->content_type);
|
|
|
|
if (stExt)
|
|
StrAllocCat (pSuggested, aExt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!pSuggested)
|
|
pSuggested = fe_URLtoLocalName(pUrl->address, pUrl->content_type);
|
|
#ifdef XP_WIN16
|
|
char dosName[13];
|
|
FE_LongNameToDosName(dosName, pSuggested);
|
|
pDestination = wfe_GetSaveFileName(GetFrame(pContext)->GetFrameWnd()->m_hWnd, szLoadString(IDS_SAVE_AS), dosName, NULL);
|
|
#else
|
|
pDestination = wfe_GetSaveFileName(GetFrame(pContext)->GetFrameWnd()->m_hWnd, szLoadString(IDS_SAVE_AS), pSuggested, NULL);
|
|
#endif
|
|
if(pSuggested != NULL) {
|
|
XP_FREE(pSuggested);
|
|
}
|
|
if(pDestination == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
// We're going to be saving this stream.
|
|
// Check to see if we should attempt to save the file in the
|
|
// old fashion, or in the new external contexts.
|
|
if(NET_IsSafeForNewContext(pUrl) != FALSE) {
|
|
// Attempt to split it off into a new context.
|
|
pRetval = CSaveCX::SaveUrlObject(pUrl, NULL, pDestination);
|
|
|
|
} else {
|
|
// We need to continue to use the old method of saving.
|
|
|
|
// We have a destination file name.
|
|
FILE *pSink = XP_FileOpen(pDestination, xpTemporary, "wb");
|
|
if(pSink == NULL) {
|
|
FE_Alert(pContext, szLoadString(IDS_FAILED_CREATE_TEMP_FILE));
|
|
XP_FREE(pDestination);
|
|
return(NULL);
|
|
}
|
|
|
|
// Create the data object that will be passed along down
|
|
// the stream.
|
|
DataObject *pMe = new DataObject;
|
|
if(!pMe)
|
|
return(NULL);
|
|
|
|
memset(pMe, 0, sizeof(DataObject));
|
|
pMe->how_handle = HANDLE_SAVE;
|
|
pMe->fp = pSink;
|
|
pMe->context = pContext;
|
|
pMe->format_out = iFormatOut;
|
|
pMe->filename = pDestination;
|
|
pMe->content_length = pUrl->content_length < 0 ? 0 : pUrl->content_length;
|
|
pMe->cur_loc = 0;
|
|
StrAllocCopy(pMe->address, pUrl->address);
|
|
StrAllocCopy(pMe->format_in, pUrl->content_type);
|
|
|
|
// Progress.
|
|
FE_SetProgressBarPercent(pContext, 0);
|
|
|
|
// Set the waiting mode???
|
|
FE_EnableClicking(pContext);
|
|
|
|
// Create the stream.
|
|
pRetval = NET_NewStream("ServeAndSave",
|
|
disk_stream_write,
|
|
disk_stream_complete,
|
|
disk_stream_abort,
|
|
write_ready,
|
|
pMe,
|
|
pContext);
|
|
|
|
if(!pRetval)
|
|
return(NULL);
|
|
}
|
|
|
|
return pRetval;
|
|
}
|
|
|
|
/* Subclass-specific Methods
|
|
** -------------------------
|
|
*/
|
|
|
|
/* this is the main converter for external viewers.
|
|
* it returns the stream object as well
|
|
* as a data object that it can reference
|
|
* internally to save the state of the document
|
|
*/
|
|
NET_StreamClass *external_viewer_disk_stream(int iFormatOut, void *pDataObj, URL_Struct *pUrl, MWContext *pContext)
|
|
{
|
|
ASSERT(pUrl);
|
|
ASSERT(pUrl->address);
|
|
|
|
// Lookup the helper app, if one exists.
|
|
// If not found, create one on the fly.
|
|
CNetscapeApp *pNetscape = (CNetscapeApp *)AfxGetApp();
|
|
CHelperApp *pHelper;
|
|
XP_Bool isNewHelper = FALSE;
|
|
|
|
if(0 == pNetscape->m_HelperListByType.Lookup(pUrl->content_type, (CObject *&)pHelper)) {
|
|
// couldn't find one.
|
|
// create the new mime type.
|
|
CString csText = pUrl->content_type;
|
|
|
|
// If there's no slash, just send the type as the file type
|
|
// (this usually only happens on server error, but we
|
|
// should still behave ourselves).
|
|
int iSlash = csText.Find('/');
|
|
if(iSlash != -1) {
|
|
// this mess splits the string into the stuff before the slash and
|
|
// the stuff after the slash
|
|
pHelper = fe_AddNewFileFormatType(csText.Left(iSlash),
|
|
csText.Right(csText.GetLength() - iSlash - 1));
|
|
isNewHelper = TRUE;
|
|
}
|
|
else {
|
|
pHelper = fe_AddNewFileFormatType(csText, "");
|
|
isNewHelper = TRUE;
|
|
}
|
|
}
|
|
|
|
// The helper app is now defined for the mime type in any case.
|
|
// See how it is to be handled.
|
|
BOOL bExternal = FALSE;
|
|
BOOL bSave = FALSE;
|
|
BOOL bMoreInfo = FALSE;
|
|
|
|
switch(pHelper->how_handle) {
|
|
case HANDLE_UNKNOWN: {
|
|
// See what this is supposed to do via user input.
|
|
CFrameWnd *pFrame = NULL;
|
|
CFrameGlue *pGlue = GetFrame(pContext);
|
|
if(pGlue) {
|
|
pFrame = pGlue->GetFrameWnd();
|
|
}
|
|
else {
|
|
pFrame = FEU_GetLastActiveFrame(MWContextAny, TRUE);
|
|
}
|
|
CUnknownTypeDlg dlgUnknown(pFrame, pUrl->content_type, pHelper);
|
|
int iDlg = dlgUnknown.DoModal();
|
|
if(iDlg == IDCANCEL) {
|
|
// User hit cancel. Abort the load.
|
|
if (pHelper && pHelper->cd_item && isNewHelper) {
|
|
if (XP_ListRemoveObject(cinfo_MasterListPointer(), pHelper->cd_item)) {
|
|
if (pHelper->cd_item) {
|
|
if (pHelper->cd_item->ci.type) {
|
|
theApp.m_HelperListByType.RemoveKey(pHelper->cd_item->ci.type);
|
|
XP_FREE( pHelper->cd_item->ci.type );
|
|
}
|
|
XP_FREE (pHelper->cd_item);
|
|
}
|
|
delete pHelper;
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
else if(iDlg == HANDLE_EXTERNAL) {
|
|
char buf[256];
|
|
|
|
bExternal = TRUE;
|
|
|
|
// We need to indicate that this is a user-defined MIME type. If we
|
|
// don't, then we won't remember it the next time the Navigator is run
|
|
sprintf(buf,"TYPE%d",theApp.m_iNumTypesInINIFile);
|
|
theApp.m_iNumTypesInINIFile++;
|
|
theApp.WriteProfileString("Viewers", buf, pUrl->content_type);
|
|
pHelper->bNewType = FALSE;
|
|
|
|
}
|
|
else if(iDlg == HANDLE_SAVE) {
|
|
bSave = TRUE;
|
|
}
|
|
else if(iDlg == HANDLE_MOREINFO) {
|
|
bMoreInfo = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case HANDLE_EXTERNAL:
|
|
case HANDLE_BY_OLE: {
|
|
bExternal = TRUE;
|
|
break;
|
|
}
|
|
case HANDLE_SHELLEXECUTE: {
|
|
bExternal = TRUE;
|
|
break;
|
|
}
|
|
case HANDLE_SAVE: {
|
|
bSave = TRUE;
|
|
break;
|
|
}
|
|
default: {
|
|
// Shouldn't ever be other than the above types at this
|
|
// point!
|
|
ASSERT(0);
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
// We know that we are either saving or spawning an external
|
|
// viewer at this point.
|
|
NET_StreamClass *pRetval = NULL;
|
|
if (bSave == TRUE) {
|
|
return ExternalFileSave(iFormatOut, pUrl, pContext);
|
|
} else if (bExternal == TRUE) {
|
|
// Prompt the user for a file name.
|
|
// Security rist to let path information in externally provided
|
|
// filename (content disposition, filename =)
|
|
// XXX This code could be cleaned up -- eliminate aFileName
|
|
// and just use what was allocated by WH_TempFileName.
|
|
|
|
char aFileName[_MAX_PATH];
|
|
char *pSuggestedName = NULL;
|
|
BOOL bUseContentName = FALSE;
|
|
if (pUrl->content_name != NULL &&
|
|
strstr(pUrl->content_name, "../") == NULL &&
|
|
strstr(pUrl->content_name, "..\\") == NULL) {
|
|
bUseContentName = TRUE;
|
|
}
|
|
else {
|
|
pSuggestedName = fe_URLtoLocalName(pUrl->address, pUrl->content_type);
|
|
}
|
|
char *pDestination;
|
|
|
|
ASSERT(pNetscape->m_pTempDir);
|
|
if(pNetscape->m_pTempDir != NULL && pSuggestedName != NULL) {
|
|
sprintf(aFileName, "%s\\%s", pNetscape->m_pTempDir, pSuggestedName);
|
|
XP_FREE(pSuggestedName);
|
|
pSuggestedName = NULL;
|
|
pDestination = aFileName;
|
|
}
|
|
else {
|
|
char aExt[_MAX_EXT];
|
|
size_t stExt = 0;
|
|
DWORD dwFlags = 0;
|
|
const char *pName = pUrl->address;
|
|
|
|
if(bUseContentName) {
|
|
pName = pUrl->content_name;
|
|
}
|
|
#ifdef XP_WIN16
|
|
dwFlags |= EXT_DOT_THREE;
|
|
#endif
|
|
aExt[0] = '\0';
|
|
stExt = EXT_Invent(aExt, sizeof(aExt), dwFlags, pName, pUrl->content_type);
|
|
char *pTemp = WH_TempFileName(xpTemporary, "M", aExt);
|
|
if(pTemp) {
|
|
strcpy(aFileName, pTemp);
|
|
XP_FREE(pTemp);
|
|
pTemp = NULL;
|
|
}
|
|
else {
|
|
aFileName[0] = '\0';
|
|
}
|
|
}
|
|
pDestination = aFileName;
|
|
|
|
|
|
// Figure out the application that we'll be spawning.
|
|
// Strip off odd things at the right hand side.
|
|
CString csCommand;
|
|
if(pHelper->how_handle == HANDLE_EXTERNAL) {
|
|
csCommand = pHelper->csCmd;
|
|
int iStrip = csCommand.ReverseFind('%');
|
|
if(iStrip > 0) {
|
|
csCommand = csCommand.Left(iStrip - 1);
|
|
}
|
|
}
|
|
|
|
// See if it's actually OK to spawn this application.
|
|
CString csSpawn = csCommand;
|
|
BOOL bShellExecute = FALSE;
|
|
if(pHelper->how_handle == HANDLE_SHELLEXECUTE ||
|
|
pHelper->how_handle == HANDLE_BY_OLE) {
|
|
// Shell execute type, figure out the exe.
|
|
char aExe[_MAX_PATH];
|
|
memset(aExe, 0, sizeof(aExe));
|
|
if(FEU_FindExecutable(pDestination, aExe, FALSE)) {
|
|
csSpawn = aExe;
|
|
if(pHelper->how_handle == HANDLE_SHELLEXECUTE) {
|
|
bShellExecute = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
csSpawn.Empty();
|
|
}
|
|
}
|
|
|
|
// See whether the user wants to be prompted before we open the file
|
|
if (pContext->type != MWContextPrint && theApp.m_pSpawn->PromptBeforeOpening((LPCSTR)csSpawn)) {
|
|
BOOL bFree = FALSE;
|
|
LPCSTR lpszFilename = NULL;
|
|
|
|
if (pUrl->content_name != NULL &&
|
|
strstr(pUrl->content_name, "../") == NULL &&
|
|
strstr(pUrl->content_name, "..\\") == NULL) {
|
|
lpszFilename = pUrl->content_name;
|
|
}
|
|
|
|
if (!lpszFilename) {
|
|
lpszFilename = fe_URLtoLocalName(pUrl->address, pUrl->content_type);
|
|
bFree = TRUE;
|
|
}
|
|
char* docExt[1];
|
|
const char * ptr1 = lpszFilename;
|
|
int type = NET_URL_Type(pUrl->address);
|
|
BOOL canHandleOLE = FALSE;
|
|
|
|
if ((type != MAILBOX_TYPE_URL) && (type !=NEWS_TYPE_URL) && (type != IMAP_TYPE_URL) ) {
|
|
docExt[0] = FE_FindFileExt((char*)ptr1);
|
|
if (docExt[0])
|
|
canHandleOLE = fe_CanHandleByOLE(docExt, 1);
|
|
}
|
|
CLaunchHelper dlg(lpszFilename, (LPCSTR)csSpawn, canHandleOLE, GetFrame(pContext)->GetFrameWnd());
|
|
|
|
if (bFree)
|
|
XP_FREE((LPVOID)lpszFilename);
|
|
|
|
// Initialize the dialog to some defaults.
|
|
dlg.m_bAlwaysAsk = TRUE;
|
|
//dlg.m_nAction = HELPER_SAVE_TO_DISK; //Old statement CRN_MIME
|
|
dlg.m_nAction = (pHelper->how_handle == HANDLE_SHELLEXECUTE) ? HELPER_OPEN_IT : HELPER_SAVE_TO_DISK; //New Statement. Set m_nAction based on pHelper->how_handle... CRN_MIME
|
|
dlg.m_bHandleByOLE = fe_IsHandleByOLE(pUrl->content_type);
|
|
|
|
// Ask the user
|
|
if (dlg.DoModal() == IDCANCEL)
|
|
return NULL;
|
|
|
|
// See if they no longer want to be asked
|
|
if (!dlg.m_bAlwaysAsk) {
|
|
if (dlg.m_nAction == HELPER_SAVE_TO_DISK) {
|
|
// User wants to just save to disk
|
|
pHelper->how_handle = HANDLE_SAVE;
|
|
pHelper->csCmd = MIME_SAVE;
|
|
pHelper->bChanged = TRUE;
|
|
|
|
} else {
|
|
ASSERT(dlg.m_nAction == HELPER_OPEN_IT);
|
|
theApp.m_pSpawn->SetPromptBeforeOpening((LPCSTR)csSpawn, FALSE);
|
|
}
|
|
}
|
|
|
|
// Check whether the user wants to launch the application or save it
|
|
// do disk
|
|
if (dlg.m_nAction == HELPER_SAVE_TO_DISK)
|
|
return ExternalFileSave(iFormatOut, pUrl, pContext);
|
|
else { // open it case.
|
|
// user want to handle this by OLE.
|
|
if (dlg.m_bHandleByOLE) {
|
|
fe_SetHandleByOLE(pUrl->content_type, pHelper, TRUE);
|
|
}
|
|
// Since mail and new will not be able launch using OLE inplace server, so we should not try to change helper app
|
|
// how_handle here.
|
|
else if (pHelper->how_handle == HANDLE_BY_OLE) {
|
|
fe_SetHandleByOLE(pUrl->content_type, pHelper, FALSE);
|
|
}
|
|
}
|
|
}
|
|
// MWH -- see could we handle this via OLE.
|
|
if ((iFormatOut == FO_PRESENT || iFormatOut == FO_PRINT) &&
|
|
(pHelper->how_handle == HANDLE_BY_OLE) &&
|
|
FE_FileType(pUrl->address, pUrl->content_type, pUrl->content_encoding)) {
|
|
|
|
// can be handle by OLE.
|
|
return OLE_ViewStream(iFormatOut, pDataObj, pUrl,pContext);
|
|
}
|
|
|
|
// It's OK to spawn this application.
|
|
// Attempt to split it off into a seperate context.
|
|
if(bShellExecute) {
|
|
pRetval = CSaveCX::ViewUrlObject(pUrl, NULL);
|
|
}
|
|
else {
|
|
pRetval = CSaveCX::ViewUrlObject(pUrl, csSpawn);
|
|
}
|
|
if(pRetval != NULL) {
|
|
return(pRetval);
|
|
}
|
|
// Couldn't split off into a new context.
|
|
// Handle as was handled before.
|
|
|
|
// We have a destination file name.
|
|
FILE *pSink = XP_FileOpen(pDestination, xpTemporary, "wb");
|
|
if(pSink == NULL) {
|
|
FE_Alert(pContext, szLoadString(IDS_FAILED_CREATE_TEMP_FILE));
|
|
XP_FREE(pDestination);
|
|
return(NULL);
|
|
}
|
|
|
|
// Create the data object that will be passed along down
|
|
// the stream.
|
|
DataObject *pMe = new DataObject;
|
|
if(!pMe)
|
|
return(NULL);
|
|
|
|
memset(pMe, 0, sizeof(DataObject));
|
|
pMe->how_handle = pHelper->how_handle;
|
|
pMe->fp = pSink;
|
|
pMe->context = pContext;
|
|
pMe->format_out = iFormatOut;
|
|
pMe->filename = pDestination;
|
|
pMe->content_length = pUrl->content_length < 0 ? 0 : pUrl->content_length;
|
|
pMe->cur_loc = 0;
|
|
StrAllocCopy(pMe->address, pUrl->address);
|
|
StrAllocCopy(pMe->format_in, pUrl->content_type);
|
|
|
|
// The spawn command.
|
|
if(pMe->how_handle == HANDLE_EXTERNAL) {
|
|
pMe->params = XP_STRDUP(pDestination);
|
|
}
|
|
else if(pMe->how_handle == HANDLE_SHELLEXECUTE) {
|
|
csCommand += pDestination;
|
|
}
|
|
else if(pMe->how_handle == HANDLE_BY_OLE) {
|
|
csCommand += pDestination;
|
|
}
|
|
pMe->command = XP_STRDUP(csCommand);
|
|
|
|
// Progress.
|
|
FE_SetProgressBarPercent(pContext, 0);
|
|
|
|
// Delete the file on exit.
|
|
FE_DeleteFileOnExit(pDestination, pUrl->address);
|
|
|
|
// Set the waiting mode???
|
|
FE_EnableClicking(pContext);
|
|
|
|
// Create the stream.
|
|
pRetval = NET_NewStream("ServeAndView",
|
|
disk_stream_write,
|
|
disk_stream_complete,
|
|
disk_stream_abort,
|
|
write_ready,
|
|
pMe,
|
|
pContext);
|
|
|
|
}
|
|
if(bMoreInfo == TRUE) {
|
|
char * url = NULL;
|
|
int iError = PREF_CopyConfigString("internal_url.more_info_plugin.url",&url);
|
|
if (PREF_ERROR != iError && url) {
|
|
CString csUrlAddress = url;
|
|
csUrlAddress += "?";
|
|
csUrlAddress += pUrl->content_type;
|
|
(ABSTRACTCX(pContext))->NormalGetUrl(csUrlAddress, pUrl->address, csUrlAddress);
|
|
XP_FREE(url);
|
|
}
|
|
}
|
|
|
|
// Return the stream that was created.
|
|
return(pRetval);
|
|
}
|
|
|
|
/****************************************************************************
|
|
MEMORY STREAM DECLARATION
|
|
*****************************************************************************/
|
|
|
|
/* Buffer write.
|
|
** ------------
|
|
*/
|
|
extern "C" int
|
|
memory_stream_write (NET_StreamClass *stream, const char* s, int32 l)
|
|
{
|
|
DataObject * data = (DataObject *)stream->data_object;
|
|
|
|
ASSERT(data);
|
|
ASSERT(s);
|
|
|
|
if(!data || !data->start || !data->loc)
|
|
return(MK_OUT_OF_MEMORY);
|
|
|
|
/* check the sizes - make bigger and recopy if needed */
|
|
if(((unsigned long)(data->loc - data->start)) + l > (unsigned long)data->sz) {
|
|
char * buffer;
|
|
int oldcontents = data->loc - data->start;
|
|
|
|
data->sz += DEFAULT_BUFFER_SZ;
|
|
buffer = (char *) XP_REALLOC(data->start, data->sz);
|
|
if(!buffer) {
|
|
XP_FREE(data->start);
|
|
data->start = NULL;
|
|
data->loc = NULL;
|
|
return(MK_OUT_OF_MEMORY);
|
|
}
|
|
|
|
data->start = buffer;
|
|
data->loc = data->start + oldcontents;
|
|
}
|
|
|
|
/* copy the stuff over and update the pointer */
|
|
XP_BCOPY(s, data->loc, l);
|
|
data->loc += l;
|
|
|
|
data->cur_loc += l;
|
|
|
|
float fPercent = 0.0f;
|
|
|
|
if (data->content_length)
|
|
fPercent = (float)data->cur_loc / (float)data->content_length;
|
|
if (data->cur_loc)
|
|
FE_SetProgressBarPercent(data->context, (int)(fPercent * 100));
|
|
|
|
return((int) l);
|
|
}
|
|
|
|
/*
|
|
* Do something interesting with the object and free it
|
|
* ----------------------------------------------------
|
|
*/
|
|
extern "C" void
|
|
memory_stream_complete (NET_StreamClass *stream)
|
|
{
|
|
DataObject * data = (DataObject *)stream->data_object;
|
|
|
|
if(data->address)
|
|
XP_FREE(data->address);
|
|
|
|
// Make sure we are text and NULL terminated
|
|
if(data->loc)
|
|
*(data->loc) = '\0';
|
|
|
|
if(data->start) {
|
|
XP_FREE(data->start);
|
|
data->start = NULL;
|
|
}
|
|
|
|
if(data->params) {
|
|
XP_FREE(data->params);
|
|
data->params = NULL;
|
|
}
|
|
|
|
delete data;
|
|
return;
|
|
}
|
|
|
|
/* End writing
|
|
*/
|
|
|
|
extern "C" void
|
|
memory_stream_abort (NET_StreamClass *stream, int status)
|
|
{
|
|
memory_stream_complete(stream);
|
|
}
|
|
|
|
|
|
/* Subclass-specific Methods
|
|
** -------------------------
|
|
*/
|
|
|
|
/* this is the main converter.
|
|
* it returns the stream object as well
|
|
* as a data object that it can reference
|
|
* internally to save the state of the document
|
|
*/
|
|
|
|
NET_StreamClass*
|
|
memory_stream (int format_out,
|
|
void *data_object,
|
|
URL_Struct *URL_s,
|
|
MWContext *context)
|
|
{
|
|
DataObject* me;
|
|
NET_StreamClass* stream;
|
|
|
|
//
|
|
// If we are a view source stream and the user wants an external view source
|
|
// application send it there instead
|
|
//
|
|
const char * html = theApp.m_pHTML;
|
|
if((format_out == FO_VIEW_SOURCE) && html && * html) {
|
|
return (view_source_disk_stream(format_out, data_object, URL_s, context));
|
|
}
|
|
else if(format_out & FO_VIEW_SOURCE) {
|
|
// Otherwise, use our colored syntax HTML viewer for view source.
|
|
return(INTL_ConvCharCode(format_out, URL_s->content_type, URL_s, context));
|
|
}
|
|
|
|
me = new DataObject;
|
|
if(!me)
|
|
return NULL;
|
|
memset(me, 0, sizeof(DataObject));
|
|
|
|
stream = NET_NewStream("MemoryWriter",
|
|
memory_stream_write,
|
|
memory_stream_complete,
|
|
memory_stream_abort,
|
|
write_ready,
|
|
me,
|
|
context);
|
|
|
|
if(stream == NULL) {
|
|
delete me;
|
|
return NULL;
|
|
}
|
|
|
|
me->context = context;
|
|
me->address = me->filename = me->format_in = NULL;
|
|
me->format_out = format_out;
|
|
StrAllocCopy(me->address, URL_s->address);
|
|
StrAllocCopy(me->format_in, URL_s->content_type);
|
|
|
|
/* set up the buffer fields */
|
|
me->sz = DEFAULT_BUFFER_SZ;
|
|
me->start = me->loc = (char *)XP_ALLOC(sizeof(char) * me->sz);
|
|
|
|
if(!me->start) {
|
|
delete me;
|
|
XP_FREE(stream);
|
|
return NULL;
|
|
}
|
|
|
|
if (URL_s->content_length > 0)
|
|
me->content_length = URL_s->content_length;
|
|
else
|
|
me->content_length = 0;
|
|
|
|
me->cur_loc =0;
|
|
FE_SetProgressBarPercent(context, 0);
|
|
|
|
return stream;
|
|
}
|
|
|
|
|
|
/* this is the main converter for saving files
|
|
* it returns the stream object as well
|
|
* as a data object that it can reference
|
|
* internally to save the state of the document
|
|
*/
|
|
PUBLIC NET_StreamClass*
|
|
view_source_disk_stream(int format_out,
|
|
void *lous_new_stuff,
|
|
URL_Struct *URL_s,
|
|
MWContext * context)
|
|
{
|
|
DataObject* me;
|
|
NET_StreamClass* stream;
|
|
FILE * fp = NULL;
|
|
BOOL bPromptUserForName =FALSE;
|
|
BOOL bDeleteFile = TRUE;
|
|
|
|
ASSERT(context);
|
|
|
|
me = new DataObject;
|
|
if (me == NULL)
|
|
return NULL;
|
|
memset(me, 0, sizeof(DataObject));
|
|
|
|
stream = NET_NewStream("FileWriter",
|
|
disk_stream_write,
|
|
disk_stream_complete,
|
|
disk_stream_abort,
|
|
write_ready,
|
|
me,
|
|
context);
|
|
|
|
if(stream == NULL) {
|
|
delete me;
|
|
return NULL;
|
|
}
|
|
|
|
// user selected save to disk
|
|
me->how_handle = HANDLE_EXTERNAL;
|
|
|
|
//
|
|
// Get a filename with an extension cuz stupid old notepad assumes one
|
|
//
|
|
char* fname = WH_TempFileName(xpTemporary, NULL, ".txt");
|
|
if(!fname)
|
|
return(NULL);
|
|
|
|
//
|
|
// Open the file in text mode so that will get return translation
|
|
// Why in the world are we doing this AnsiToOemBuff stuff???
|
|
//
|
|
#ifdef XP_WIN32
|
|
fp = fopen(fname, "wt");
|
|
#else
|
|
char oemBuff[254];
|
|
AnsiToOemBuff(fname, oemBuff, strlen(fname)+1);
|
|
fp = fopen(oemBuff, "wt");
|
|
#endif
|
|
if(!fp) {
|
|
XP_FREE(fname);
|
|
return NULL;
|
|
}
|
|
|
|
// delete the file when we are done
|
|
FE_DeleteFileOnExit(fname, URL_s->address);
|
|
|
|
int len = theApp.m_pHTML.GetLength() + XP_STRLEN(fname) + 10;
|
|
me->command = (char *) XP_ALLOC(len);
|
|
if(!me->command) {
|
|
fclose(fp);
|
|
XP_FREE(fname);
|
|
return NULL;
|
|
}
|
|
|
|
sprintf(me->command, "%s %s", theApp.m_pHTML, fname);
|
|
|
|
me->fp = fp;
|
|
me->address = me->filename = me->format_in = NULL;
|
|
me->context = context;
|
|
me->format_out = format_out;
|
|
me->filename = fname;
|
|
StrAllocCopy(me->address, URL_s->address);
|
|
StrAllocCopy(me->format_in, URL_s->content_type);
|
|
|
|
FE_EnableClicking(context);
|
|
|
|
if (URL_s->content_length > 0)
|
|
me->content_length = URL_s->content_length;
|
|
else
|
|
me->content_length = 0;
|
|
|
|
FE_SetProgressBarPercent(context, 0);
|
|
|
|
return stream;
|
|
|
|
}
|