gecko-dev/cmd/winfe/display.cpp
1998-07-24 22:56:50 +00:00

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;
}