pjs/cmd/macfe/central/msv2dsk.cp

1039 строки
26 KiB
C++
Исходник Обычный вид История

1998-03-28 05:44:41 +03:00
/* -*- 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.
*/
// Macintosh front-end
#include "msv2dsk.h"
#include "earlmgr.h"
#include "macutil.h"
#include "uerrmgr.h"
#include "uprefd.h"
#include "ufilemgr.h"
#include "ulaunch.h"
#include "macutil.h"
#include "resgui.h"
#include "prefwutil.h"
#include "uapp.h"
#include "resae.h"
#include "CNSContext.h"
#include "CDownloadProgressWindow.h"
// Netscape
#include "merrors.h"
#include "xp_thrmo.h"
#include "mkutils.h"
#include "glhist.h"
#include "xlate.h"
#include "prefapi.h"
#include "BufferStream.h"
#include "PascalString.h"
// system
#include <StandardFile.h>
#include "merrors.h"
1998-06-23 05:36:59 +04:00
#include "InternetConfig.h"
1998-03-28 05:44:41 +03:00
static Boolean GetMacFileTypesFromMimeHeader( const URL_Struct * fRequest,
OSType * fileCreator,
OSType * fileType );
static OSType TextToOSType( const char* text);
extern int MK_DISK_FULL;
extern CMimeMapper * CreateUnknownMimeTypeMapper (URL_Struct * request);
extern void GUI_PostAlertNoReply (const CStr255 & message);
extern OSErr GUI_AskForFileSpec (StandardFileReply & reply);
/*------------------=----------------------------------------------------------
External function so everyone can start a progress load without having
to include the full .h file
--------------------=--------------------------------------------------------*/
extern "C" void SaveAsCompletionProc( PrintSetup* p );
extern "C" void SaveAsCompletionProc( PrintSetup* p )
{
XP_FileClose (p->out);
CNSContext* theContext = (CNSContext*)p->url->fe_data;
// FIX ME!!! need to put this back in
// if (theContext != NULL)
// theContext->AllConnectionsComplete();
}
extern int MK_OUT_OF_MEMORY;
int PROGRESS_GetUrl(
URL_Struct *,
int /*format_out*/,
const FSSpec * /*destination*/,
Boolean /*delayed*/)
{
Assert_(false); // NO LONGER VALID
return 0;
}
/*-----------------------------------------------------------------------------
When we decide to do something with an url (such as save it to disk, print
it, mail it, etc), we sometimes have extra data which specializes the
action. Save-to-disk is the best example: a destination file. We need a
place to put it all.
We have been putting this data in the context. This is a mistake because
the context is not specific to any particular url action, and multiple
requests will cause a race condition.
The url struct is where it belongs, since this object is created at that
time (making it like MacApp's Command class). It has an fe_data field,
but we need to put *lots* of data there. Argh.
Things go to disk when we launch an external viewer (click -> download in
normal context) or explicitly request a download (SAVE_AS, SAVE_TO_DISK,
VIEW_SOURCE, and Drag&Drop).
FO_PRESENT auto-launch external viewer (by normal click).
VIEW_SOURCE auto-launch with view source application
SAVE_TO_DISK prompt for location and save to disk
SAVE_AS prompt for location and save to disk
INTERNAL_IMAGE display internally.
Drag&Drop Variant of SAVE_TO_DISK
SAVE_ALL Save page & images. Like SAVE_AS.
-----------------------------------------------------------------------------*/
class DownloadFilePipe: public Pipe
{
public:
DownloadFilePipe (
CNSContext* progressContext,
URL_Struct* request);
~DownloadFilePipe ();
OSErr Open ();
int Write (const char *buffer, int len);
void Complete ();
void Abort (int reason);
OSErr GetFileSpec ();
inline Boolean TranslateLinefeeds ();
Boolean LaunchWhenDone ();
CNSContext* mContext;
protected:
URL_Struct * fRequest;
NET_StreamClass * fInput;
// fFile logic gets complicated. There are two questions:
// - where to create the file
// - when should the file object be deleted
// - when should the file be deleted
// The answers depend upon the stream:
// case FO_PRESENT:
// ask mapper for the registered viewer file spec.
// if we get these specs, registered viewer will handle the physical file deletion
// we need to delete the fFile object
// else, do the same as
// case FO_VIEW_SOURCE:
// register with the app, do not delete fFile yourself
// case FO_SAVE_AS:
// do not register, delete file object -
LFileBufferStream * fFile;
Boolean fDeleteOnDestroy; // Should we delete the file object?
int fIntention;
CMimeMapper * fHandler;
Boolean fHasDestination;
FSSpec fDestination;
OSErr GetSilentFileSpec();
OSErr GetUserFileSpec();
friend NET_StreamClass * NewFilePipe (int format_out, void *registration, URL_Struct * request, MWContext *context);
};
static LArray DownloadList; // Keeps track of all downloads, so that we can see if we are interrupting any
Boolean HasDownloads(MWContext * context)
{
DownloadFilePipe * pipe;
LArrayIterator iter(DownloadList);
while (iter.Next(&pipe))
{
MWContext* theContext = *(pipe->mContext);
if (theContext == context)
return true;
}
return false;
}
//--------------------------------------------------------------------------------
// DownloadFilePipe
//--------------------------------------------------------------------------------
DownloadFilePipe::DownloadFilePipe (
CNSContext* progressContext,
URL_Struct* request)
{
mContext = progressContext;
mContext->AddUser(this);
fRequest = request;
fInput = nil;
fFile = nil;
fIntention = -1;
fHandler = nil;
fHasDestination = false;
fDeleteOnDestroy = true;
DownloadList.InsertItemsAt(1,1,&this);
}
DownloadFilePipe::~DownloadFilePipe ()
{
mContext->RemoveUser(this);
if (fFile && fDeleteOnDestroy)
{
CFileMgr::sFileManager.CancelRegister(fFile);
delete fFile;
}
Int32 where = DownloadList.FetchIndexOf(&this);
DownloadList.RemoveItemsAt(1,where);
}
OSErr DownloadFilePipe::GetSilentFileSpec()
{
OSErr err;
1998-06-23 05:36:59 +04:00
//CStr31 defaultName = CFileMgr::FileNameFromURL( fRequest->address );
CStr31 defaultName;
if( fRequest->content_name )
{
char* fileName = XP_STRDUP ( fRequest->content_name );
if ( fileName )
SwapSlashColon( fileName );
defaultName = fileName;
XP_FREEIF( fileName );
}
1998-03-28 05:44:41 +03:00
else
defaultName = CFileMgr::FileNameFromURL( fRequest->address ) ;
1998-06-23 05:36:59 +04:00
FSSpec defaultFolder;
1998-03-28 05:44:41 +03:00
defaultFolder = CPrefs::GetFilePrototype( CPrefs::DownloadFolder );
err = CFileMgr::UniqueFileSpec( defaultFolder, defaultName, fDestination );
if ( err )
return err;
fDeleteOnDestroy = FALSE;
fHasDestination = TRUE;
return noErr;
}
// Get specs from the user
OSErr DownloadFilePipe::GetUserFileSpec()
{
OSErr err;
1998-06-23 05:36:59 +04:00
CStr31 defaultName;
if( fRequest->content_name )
1998-03-28 05:44:41 +03:00
defaultName = fRequest->content_name;
else
defaultName = CFileMgr::FileNameFromURL( fRequest->address ) ;
1998-06-23 05:36:59 +04:00
StandardFileReply reply;
1998-03-28 05:44:41 +03:00
(CStr63&)reply.sfFile.name = defaultName;
err = GUI_AskForFileSpec( reply );
if ( err )
return err;
fDestination = reply.sfFile;
fHasDestination = TRUE;
fDeleteOnDestroy = TRUE; // do not delete automatically
return noErr;
}
// Obtain the location of where the stream should be downloaded to
OSErr DownloadFilePipe::GetFileSpec ()
{
OSErr err = noErr;
if (fHasDestination)
fDeleteOnDestroy = true;
else
{
// case FO_PRESENT:
// ask mapper for the registered viewer file spec.
// if we get these specs, registered viewer will handle the physical file deletion
// we need to delete the fFile object
// else, do the same as
// case FO_VIEW_SOURCE:
// register with the app, do not delete fFile yourself
// case FO_SAVE_AS:
// we should have the spec already, die otherwise
switch (fIntention) {
case FO_PRESENT:
if (fHandler)
{
// See if the helper app is already running and
// has registered with us at runtime. If so,
// give it a chance to tell us where to put the file.
//
err = fHandler->GetFileSpec(fRequest, fDestination);
// tj, with mourey and timm:
//
// This wasn't guarded by fHandler but we're sure it should be.
// We should only delete on destroy if the helper app has registered
// with us at runtime and tells us where to save the file. Otherwise,
// we need to prompt for the file name/location.
//
// This never used to be a problem because fHandler was never NULL.
// Now with support for mac type/creator from the mime header, fHandler
// may be NULL.
if (err == noErr)
{
fDeleteOnDestroy = true;
break;
}
}
if (LaunchWhenDone())
err = GetSilentFileSpec();
else
err = GetUserFileSpec();
break;
case FO_SAVE_AS:
err = GetUserFileSpec();
break;
case FO_VIEW_SOURCE:
err = GetSilentFileSpec();
break;
default:
Assert_(false);
}
}
if (err == noErr) // No error in creating the spec, make the stream
{
try
{
fFile = new LFileBufferStream (fDestination);
}
catch (OSErr err)
{
return err;
}
fFile->DoUseBuffer();
if (fRequest && fRequest->address)
fFile->SetURL(XP_STRDUP(fRequest->address));
if (fDeleteOnDestroy == false) // If we are not taking care of the file, file manager is
CFileMgr::sFileManager.RegisterFile(fFile);
}
return err;
}
inline Boolean DownloadFilePipe::TranslateLinefeeds ()
{
return (fIntention == FO_VIEW_SOURCE);
}
Boolean DownloadFilePipe::LaunchWhenDone ()
{
/*
For view source we always want to launch the viewer.
For saving HTML, don't launch it, just save.
For drag&drop, we want to launch Stuffit (for FTP convenience) but not
a text viewer, so text/html->false, the rest according to mime mapper
*/
if (fIntention == FO_VIEW_SOURCE)
return true;
if (fIntention == FO_SAVE_AS)
return false;
if (strcmp(fRequest->content_type, "text/html") == 0) // LAM need entry for text/html!
return false;
if (fHandler != NULL)
return fHandler->GetLoadAction() == CMimeMapper::Launch;
else
return false;
}
OSErr DownloadFilePipe::Open ()
{
/*
If this is a drag&drop or SAVE_AS then we already have a filespec.
If the helper application is set to "launch" then we automatically
choose a filespec. Otherwise we have to ask.
*/
OSErr err;
cstring appName = "\0"; // app that can open the attachment
CMimeMapper * mapper = nil; // mime-type -> mac-type mapper
OSType fileType = 0; // mac file type of the attachment
OSType fileCreator = 0; // mac creator type of the attachment
//
// Figure out the appropriate file type and creator
//
if (fIntention == FO_VIEW_SOURCE || strcmp(fRequest->content_type,"text/html") == 0)
mapper = CPrefs::sMimeTypes.FindMimeType (CMimeList::HTMLViewer);
if (mapper == NULL)
{
//
// If we have content of application/octet-stream, look for the mac file type
// and creator in the URL struct (from the mime header).
//
// If we find valid mac file type/creator data, or if the content_type
// isn't octet-stream, then we attempt content_type -> mime-type mapping
//
1998-06-23 05:36:59 +04:00
// MIME content types are case insensitive
if ( (XP_STRCASECMP(fRequest->content_type, APPLICATION_OCTET_STREAM) != 0) ||
1998-03-28 05:44:41 +03:00
!GetMacFileTypesFromMimeHeader(fRequest, &fileCreator, &fileType) )
{
mapper = CPrefs::sMimeTypes.FindMimeType (fRequest->content_type);
if (mapper && mapper->GetLoadAction() == CMimeMapper::Unknown)
{
//
// If they specified "Unknown" in the prefs, then we have an existing
// mapper that tells us this fact. To know how to handle the stream
// this time, we need to ask them what to do and create a new mapper.
//
mapper = CreateUnknownMimeTypeMapper (fRequest);
if (!mapper)
return userCanceledErr;
}
else if (mapper == NULL)
{
if (!GetMacFileTypesFromMimeHeader(fRequest, &fileCreator, &fileType))
{
1998-06-23 05:36:59 +04:00
// TRY IC
// Time to call IC to see if it knows anything
ICMapEntry ICMapper;
ICError error = 0;
CStr255 saveName;
if( fRequest->content_name )
1998-03-28 05:44:41 +03:00
{
1998-06-23 05:36:59 +04:00
char* fileName = XP_STRDUP ( fRequest->content_name );
if ( fileName )
SwapSlashColon( fileName );
saveName = fileName;
XP_FREEIF( fileName );
1998-03-28 05:44:41 +03:00
}
else
1998-06-23 05:36:59 +04:00
saveName = CFileMgr::FileNameFromURL( fRequest->address ) ;
error = CInternetConfigInterface::MapFileName( saveName , &ICMapper );
if( error != icPrefNotFoundErr && StrLength(ICMapper.MIME_type) )
1998-03-28 05:44:41 +03:00
{
1998-06-23 05:36:59 +04:00
fileCreator = ICMapper.file_creator;
fileType = ICMapper.file_type;
}
else
{
if (fIntention != FO_SAVE_AS)
{
mapper = CreateUnknownMimeTypeMapper (fRequest);
if (!mapper)
return userCanceledErr;
}
else
{
fileType = 'TEXT';
fileCreator = emSignature;
}
1998-03-28 05:44:41 +03:00
}
}
}
}
}
//
// If fHandler is NULL, then fileType and fileCreator have been set
// from the mime header via GetMacFileTypesFromMimeHeader.
//
// When fHandler is NULL, appName will be empty because we're not
// doing anything further to match the file to its application
//
fHandler = mapper;
if (fHandler != NULL)
{
fileCreator = fHandler->GetAppSig();
fileType = fHandler->GetDocType();
appName = fHandler->GetAppName();
1998-06-23 05:36:59 +04:00
OSType headerCreator, headerType;
// if the file creator is the same as the one suggested by the mime mapper
// use the macheader to determine file type.
if( GetMacFileTypesFromMimeHeader(fRequest, &headerCreator, &headerType) )
{
if( headerCreator == fileCreator )
{
fileType = headerType;
}
}
1998-03-28 05:44:41 +03:00
}
// Additional little hack to make sure if we've got a text/html type file and we're supposed
// to view it internally we set it to our creator code
if (strcmp(fRequest->content_type,"text/html") == 0 &&
mapper->GetLoadAction() == CMimeMapper::Internal)
{
fileType = 'TEXT';
fileCreator = emSignature;
}
Assert_(fileCreator != (OSType) 0 && fileType != (OSType) 0);
//
// Figure out the appropriate file type and creator
//
err = GetFileSpec ();
if (err)
return err;
// Make a file object, file stream, and stream buffer.
Try_
{
// Open an existing file before creating because for drag&drop we will have
// created a Bookmark file as a placeholder. For all other cases, we have
// a unique filespec.
fFile->OpenDataFork (fsRdWrPerm);
err = CFileMgr::SetFileTypeCreator(fileCreator, fileType, &fDestination);
ThrowIfOSErr_ (err);
}
Catch_ (openErr)
{
if (openErr == fnfErr) {
fFile->CreateNewDataFile (fileCreator, fileType, smSystemScript);
fFile->OpenDataFork (fsRdWrPerm);
}
else
Throw_ (openErr);
}
EndCatch_
if (fFile && fRequest && fRequest->address)
{
FSSpec macSpec;
fFile->GetSpecifier(macSpec);
CFileMgr::FileSetComment (macSpec, CStr255(fRequest->address));
}
CStr255 message;
StringHandle messageHdl = ::GetString(SAVE_QUOTE_RESID);
if(messageHdl && *messageHdl) {
::HLock((Handle) messageHdl);
CopyString((unsigned char *) message, (const unsigned char *) *messageHdl);
::HUnlock((Handle) messageHdl);
}
message += CStr255(fDestination.name);
message += "\"";
CContextProgress* theProgress = mContext->GetCurrentProgressStats();
Assert_(theProgress != NULL);
StSharer theShareLock(theProgress);
theProgress->mAction = message;
if (LaunchWhenDone()) {
messageHdl = ::GetString(WILL_OPEN_WITH_RESID);
if(messageHdl && *messageHdl) {
::HLock((Handle) messageHdl);
CopyString((unsigned char *) message, (const unsigned char *) *messageHdl);
::HUnlock((Handle) messageHdl);
}
message += appName;
message += GetCString(WILL_OPEN_TERM_RESID);
}
else {
message = "";
messageHdl = ::GetString(SAVE_AS_A_RESID);
if(messageHdl && *messageHdl) {
::HLock((Handle) messageHdl);
CopyString((unsigned char *) message, (const unsigned char *) *messageHdl);
::HUnlock((Handle) messageHdl);
}
message += appName;
message += GetCString(FILE_RESID);
}
theProgress->mComment = message;
mContext->UpdateCurrentProgressStats();
if( fRequest->server_can_do_byteranges || fRequest->server_can_do_restart )
fRequest->must_cache = TRUE;
return noErr;
}
int
DownloadFilePipe::Write (const char *buffer, int len)
{
int written = 0;
Try_
{
if (TranslateLinefeeds()) {
for (int i = 0; i < len; i++) {
char c = buffer[i];
if (c == LF)
c = CR;
fFile->WriteData (&c, 1);
}
written = len;
}
else
written = fFile->WriteData (buffer, len);
}
Catch_ (writeErr)
{
CStr255 message = (const char*) GetCString(COULD_NOT_SAVE_RESID);
message += CStr63(fDestination.name);
if (writeErr == dskFulErr)
message += CStr255((const char*)GetCString(DISK_FULL_RESID));
else
message += CStr255((const char*)GetCString(DISK_ERR_RESID));
ErrorManager::PlainAlert(message);
return MK_DISK_FULL;
}
EndCatch_
return written;
}
// Close the file
// Launch the helper application if necessary
void DownloadFilePipe::Complete ()
{
if (fRequest)
GH_UpdateGlobalHistory(fRequest);
if (fFile)
Try_
{
fFile->CloseDataFork();
CFileMgr::UpdateFinderDisplay(fDestination);
}
Catch_(inErr){}
EndCatch_
NET_RemoveURLFromCache(fRequest);
NET_RemoveDiskCacheObjects(0);
Try_
{
if (LaunchWhenDone() && fHandler && fFile)
// fHandler->LaunchFile(fFile, fRequest, fCppContext->GetContextUniqueID());
// FIX ME!!! we need to implement the unique ID stuff in the CNSContext
fHandler->LaunchFile(fFile, fRequest, 69);
}
Catch_(inErr){}
EndCatch_
}
void DownloadFilePipe::Abort (int /*reason*/)
{
if (fFile)
{
Try_
{
fFile->CloseDataFork();
}
Catch_(inErr)
{}
EndCatch_
FSSpec fileSpec;
fFile->GetSpecifier (fileSpec);
FSpDelete (&fileSpec);
}
fDeleteOnDestroy = true;
}
/*-----------------------------------------------------------------------------
C++ URL Streams
Streams are responsible for reading data in to memory/disk
They will also get "hinting" information and be responsible for
ultimately deciding where to direct the data.
display_converter and Pipe::Handle* are called from C code. They cannot
pass any exceptions up.
-----------------------------------------------------------------------------*/
int Pipe::HandleProcess (NET_StreamClass *stream, const char *buffer, int32 buffLen)
{
void *streamData=stream->data_object;
volatile int result = -1;
Try_ {
Pipe *self = (Pipe*) streamData;
result = self->Write (buffer, buffLen);
}
Catch_ (err) {
XP_TRACE(("*** Caught an error (%i) in Pipe::HandleProcess", err));
result = -1;
}
EndCatch_
return result;
}
void Pipe::HandleComplete (NET_StreamClass *stream)
{
void *streamData=stream->data_object;
Try_ {
Pipe *self = (Pipe*) streamData;
self->Complete ();
delete self;
}
Catch_ (err) {
XP_TRACE(("*** Caught an error (%i) in Pipe::HandleComplete but can't return it", err));
}
EndCatch_
}
void Pipe::HandleAbort (NET_StreamClass *stream, int reason)
{
void *streamData=stream->data_object;
Try_ {
XP_TRACE(("*** HandleAbort %i", reason));
Pipe *self = (Pipe*) streamData;
self->Abort (reason);
delete self;
}
Catch_ (err) {
XP_TRACE(("*** Caught an error (%i) in Pipe::HandleAbort but can't return it", err));
}
EndCatch_
}
unsigned int Pipe::HandleWriteReady (NET_StreamClass * /*stream*/)
{
return 32765;
}
//
//
//
OSErr
Pipe::Open ()
{
return noErr;
}
int
Pipe::Write (const char */*buffer*/, int buffLen)
{
return buffLen;
}
void
Pipe::Complete ()
{
}
void
Pipe::Abort (int /*reason*/)
{
}
//
// api
//
NET_StreamClass *
Pipe::MakeStreamObject (char * name, MWContext * context)
{
NET_StreamClass * stream = NET_NewStream (
name,
Pipe::HandleProcess,
Pipe::HandleComplete,
Pipe::HandleAbort,
Pipe::HandleWriteReady,
this,
context);
return stream;
}
//
// Construction & Stuff
//
Pipe::Pipe ()
{
}
Pipe::~Pipe ()
{
}
CMimeMapper * CreateUnknownMimeTypeMapper(URL_Struct * request);
// After receiving the request for unknown mime type, this routine is called
// to create a mapper for an unknown MIME type
CMimeMapper* CreateUnknownMimeTypeMapper( URL_Struct* request )
{
CStr255 fileName;
CStr255 content_type;
CStr31 newName;
int result;
CMimeMapper* mapper = NULL;
if (!ErrorManager::TryToInteract(900))
return NULL;
// Notify the user with nice names
newName = CFileMgr::FileNameFromURL( request->address );
fileName = newName;
content_type = NET_URLStruct_ContentType( request );
::ParamText( newName, content_type, CStr255::sEmptyString, CStr255::sEmptyString );
UDesktop::Deactivate();
result = ::CautionAlert( ALRT_UnknownMimeType, NULL );
UDesktop::Activate();
// What does user want?
switch ( result )
{
case ALRT_UnknownMimeType_Cancel:
return NULL;
case ALRT_UnknownMimeType_Save:
mapper = CPrefs::CreateDefaultUnknownMapper( NET_URLStruct_ContentType(request), TRUE );
mapper->SetLoadAction( CMimeMapper::Save );
return mapper;
case ALRT_UnknownMimeType_PickApp:
StandardFileReply reply;
CFilePicker::DoCustomGetFile( reply, CFilePicker::Applications, FALSE );
if ( reply.sfGood )
mapper = CPrefs::CreateDefaultAppMapper( reply.sfFile,NET_URLStruct_ContentType(request), TRUE );
return mapper;
case ALRT_UnknownMimeType_MoreInfo:
{
char* string;
if (PREF_CopyConfigString("internal_url.more_info_plugin.url", &string) != PREF_NOERROR)
return NULL;
cstring url;
url = (const char*) string; // cstring<6E>s operator= expects unsigned char* to be a P string, so we have to cast
url += "?";
url += NET_URLStruct_ContentType( request );
AppleEvent getURLEvent;
UAppleEventsMgr::MakeAppleEvent( AE_url_suite, AE_url_getURL, getURLEvent );
OSErr err = ::AEPutParamPtr( &getURLEvent, keyDirectObject, typeChar, url.data(), strlen(url.data()) );
if ( err == noErr )
err = ::AEPutParamPtr( &getURLEvent, AE_url_getURLname, typeChar, url.data(), strlen(url.data()) );
if ( err == noErr )
UAppleEventsMgr::SendAppleEvent (getURLEvent );
return NULL;
}
default:
return NULL;
}
return NULL;
}
NET_StreamClass * NewFilePipe (
int format_out,
void * /*registration*/,
URL_Struct * request,
MWContext* context)
{
CNSContext* theContext = ExtractNSContext(context);
Assert_(theContext != NULL);
GH_UpdateGlobalHistory(request);
// 97-06-15 pkc -- We really should make a function to determine if a URL is a
// mail attachment instead of duplicating this code.
const char* urlAddress = request ? NET_URLStruct_Address(request) : nil;
Boolean isMailMessage = false;
if (urlAddress)
{
// check to see if this is a mail or news messages
1998-06-23 05:36:59 +04:00
if (!strncasecomp (urlAddress, "mailbox:", 8) || !strncasecomp (urlAddress, "news:", 5)
|| !strncasecomp (urlAddress, "IMAP:", 5) )
1998-03-28 05:44:41 +03:00
{
{
// this is a mail message
isMailMessage = true;
}
}
}
// 97-06-15 pkc -- The bug is that when you close the browser
// window for the mail message, the MimeObject* in the context is freed. That pointer is also
// referenced somewhere else and used by libnet. Whoops. So, since we're trying to ship, don't
// spawn a seperate progress context for mail messages.
// 97-08-15 sdagley - Removing check for theContext->IsCloneRequired() as it won't be set to true
// in frames which is the cause of bug #75288. The alternative fix is to change the CNSContext constructors
// to initialize mRequiresClone to true instead of the current default of false.
if (/*theContext->IsCloneRequired() &&*/ !isMailMessage)
{
CNSContext* theProgressContext = NULL;
CDownloadProgressWindow* theProgressWindow = NULL;
try
{
theProgressContext = new CNSContext(*theContext);
StSharer theShareLock(theProgressContext);
// 97-06-12 pkc -- Move call to NET_SetNewContext here so that if it fails
// (which can happen if mocha calls us) we still use context
if(NET_SetNewContext(request, *theProgressContext, EarlManager::DispatchFinishLoadURL) == 0)
theContext = theProgressContext;
theProgressWindow = dynamic_cast<CDownloadProgressWindow*>(LWindow::CreateWindow(WIND_DownloadProgress, LCommander::GetTopCommander()));
ThrowIfNULL_(theProgressWindow);
theProgressWindow->Show();
// theProgressWindow->SetWindowContext(theProgressContext);
theProgressWindow->SetWindowContext(theContext);
// the window will be shown upon progress initialization
}
catch(...)
{
delete theProgressWindow;
return NULL;
}
}
DownloadFilePipe* thePipe = NULL;
NET_StreamClass* theStream = NULL;
try
{
// 97-06-05 pkc -- if theContext doesn't have ContextProgress, make one now
if (!theContext->GetContextProgress())
theContext->EnsureContextProgress();
thePipe = new DownloadFilePipe(theContext, request);
thePipe->fIntention = CLEAR_CACHE_BIT(format_out);
if (request->fe_data)
{
thePipe->fDestination = *(FSSpec*)request->fe_data;
thePipe->fHasDestination = true;
XP_FREE(request->fe_data);
}
OSErr theErr = thePipe->Open();
ThrowIfOSErr_(theErr);
theStream = thePipe->MakeStreamObject("Download File", *theContext);
thePipe->fInput = theStream;
}
catch (...)
{
if (thePipe != NULL)
thePipe->Abort (-1);
delete thePipe;
XP_DELETE(theStream);
theStream = NULL;
}
return theStream;
}
//
// Snarf the mac file type and creator out of the mime header.
//
// Returns true if valid data is found, false if not.
//
static Boolean
GetMacFileTypesFromMimeHeader( const URL_Struct * fRequest,
OSType * fileCreator,
OSType * fileType )
{
*fileCreator = 0;
*fileType = 0;
Assert_(fRequest != NULL);
if ( fRequest->x_mac_creator == NULL ||
fRequest->x_mac_type == NULL )
{
return false;
}
*fileCreator = TextToOSType(fRequest->x_mac_creator);
*fileType = TextToOSType(fRequest->x_mac_type);
return (*fileCreator != 0 && *fileType != 0);
}
static OSType
TextToOSType( const char* text)
{
OSType result = 0;
UInt32 len;
//
// If the text is 4-characters long, we treat it
// as a raw OSType.
//
// If it is 8-characters, it is hex-encoded.
//
// If it's not 4 or 8, we return 0;
//
len = strlen(text);
if (len == 4)
result = * ((OSType *) text);
else
if (len == 8)
sscanf(text, "%lx", &result);
return result;
}