sys7.1-doc-wip/ProcessMgr/PackageMgrPatches.c

247 lines
7.9 KiB
C

/*
File: PackageMgrPatches.c
Contains: Routines which patch the Package Manager traps.
Written by: Erich Ringewald
Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<3> 3/31/92 DCL Include StandardFile. Because it was removed from Packages.h
<0> x/xx/86 ELR New Today.
*/
#include <types.h>
#include <memory.h>
#include <quickdraw.h>
#include <fonts.h>
#include <events.h>
#include <dialogs.h>
#include <desk.h>
#include <resources.h>
#include <osutils.h>
#include <packages.h>
#include <standardfile.h>
#include <retrace.h>
#include <menus.h>
#include <windows.h>
#include <files.h>
#include <toolutils.h>
#include <segload.h>
#include <AppleEventsInternal.h>
#include "Glue.h"
#include "Lomem.h"
#include "Data.h"
#include "SysMisc.h"
#include "Patches.h"
#include "Puppet.h"
/************************************************************************************
* Patch to SFGetFile/SFPGetFile (PACK3 selectors) for puppet string Open. This patch
* is reached after we have told the application that there was a mousedown in the menu
* bar, and then that the user selected the "Open…" item from the menu. The application
* calls PACK3, which we patch to come here. Instead of the usual modal dialog, we
* just return a specification for the file being puppet Open'd. Of course, we have to
* go through the normal hoops, like checking the type list and calling the file filter.
* NOTE: This only works with the older-style SFGetFiles that employ a Working Directory.
* The newer FSSpec-based ones are not supported, since callers using them should also
* be AppleEvent-aware, and therefore never require puppet-stringing.
************************************************************************************/
/* Some function prototypes that should be in (yet another) header file */
OSErr FileIDToAppFile(AETFDescriptor *, AppFile *, short *, long *);
void NextListParam(AETFDescriptor **);
/* Function prototypes for the application routines called by the SFGetFile handler. */
typedef pascal short (*DialogHookPtr) (short item, Ptr theDialog);
typedef pascal Boolean (*FileFilterFncPtr) (FileParam *paramBlockPtr);
/* We truncate the file names we hand back, since they are generated by puppet master. */
#define MAX_SF_FNAME_LEN (63)
/* InTypeList. Check whether the puppet file is in the typelist given to SFGetFile. */
Boolean
InTypeList(long fType, SFTypeList *pSFTypeList, short numTypes)
{
/* count of zero means all types are OK */
if (numTypes == (-1))
return(true);
/* traverse the array until type matches or the count is exhausted */
while (--numTypes >= 0)
if ((*pSFTypeList)[numTypes] == fType)
return(true);
/* Ze count he eez tired */
return(false);
}
/* AcceptedByFileFilter. Call the filter, and return whether the file is OK. */
short
AcceptedByFileFilter(AppFile *pActiveDoc, Ptr fileFilterFnc)
{
CInfoPBRec myCInfoPBRec;
unsigned long olda5;
Boolean retval;
if (fileFilterFnc == nil)
return true;
/* Get catalog info required by the filter */
myCInfoPBRec.dirInfo.ioNamePtr = &pActiveDoc->fName;
myCInfoPBRec.dirInfo.ioVRefNum = pActiveDoc->vRefNum;
myCInfoPBRec.dirInfo.ioFDirIndex = 0;
myCInfoPBRec.dirInfo.ioDrDirID = 0;
if (PBGetCatInfo(&myCInfoPBRec, SyncHFS) != noErr)
return(false);
/* Filter returns whether should be filtered! Our return value has inverse sense. */
olda5 = CurrentA5SimpleSetup();
retval = (CALL_FNC_PTR(FileFilterFncPtr, fileFilterFnc, (&myCInfoPBRec)) == false);
A5SimpleRestore(olda5);
return(retval);
}
/* CopyWDToCurProc. Given an existing Working Directory refnum, open a new WD for the
* same directory. The new copy is needed because a) the puppet master might close the
* original, and b) WDs are tagged by HFS to the process that opened them, and
* closes them when the process goes away.
*/
void
CopyWDToCurProc(short wdRefNumSrc, WDPBRec *pWDPB)
{
pWDPB->ioVRefNum = wdRefNumSrc;
pWDPB->ioWDIndex = 0;
pWDPB->ioWDProcID = 0;
pWDPB->ioNamePtr = nil;
pWDPB->ioCompletion = nil;
PBGetWDInfo(pWDPB, SyncHFS);
pWDPB->ioVRefNum = pWDPB->ioWDVRefNum;
pWDPB->ioWDProcID = 0;
pWDPB->ioNamePtr = nil;
pWDPB->ioCompletion = nil;
(void) PBOpenWD(pWDPB, SyncHFS);
}
/* IsForcedOpen. The main patch to SFGetFile. If the call to SFGetFile is to get a
* puppet file opened, set up the puppet file specification. Returns whether this
* was done.
*/
Boolean
IsForcedOpen(Ptr fileFilterFnc, short numTypes, Ptr dlgHook, SFTypeList *pSFTypeList, SFReply *pSFReply, short dlgID)
{
AppFile *pActiveDoc;
EventListPtr activeInstrsPtr;
EventListHdl activeInstrsHdl;
EventRecord *pActiveEvent;
Boolean isForcedOpen;
PuppetVars *myPuppetVarsPtr;
MFmsgBlkPtr msgBlk;
WDPBRec wdpbRec;
AppFile appFile;
short theVol;
long theDir;
long strLengthPlus1;
DialogPtr pDialog;
unsigned long olda5;
isForcedOpen = false;
olda5 = ProcessMgrA5SimpleSetup();
if (InstrsQueueIsEmpty() == false)
if ((activeInstrsHdl = GetActiveInstrsHdl()) != nil)
{
HLock(activeInstrsHdl);
activeInstrsPtr = *activeInstrsHdl;
/* Since we really look at the instruction preceding the current one */
assert((unsigned long)activeInstrsPtr->offset >= (SIZEOF_EVENTLIST_HDR + sizeof(EventRecord)));
pActiveEvent = ((Ptr) activeInstrsPtr) + (unsigned long)activeInstrsPtr->offset;
pActiveEvent--;
if (*((char *)&pActiveEvent->what + 1) == app4Evt && (*((char *)&pActiveEvent->message) == instrOpen))
{
isForcedOpen = true;
/* Make pActiveDoc->vRefNum a valid WD for the current process. Copy
* it from current WD, or open it from translation vrefnum/dirid.
*/
myPuppetVarsPtr = &pCurrentProcess->p_puppetvars;
if ((msgBlk = myPuppetVarsPtr->puppetEppcMsgBlk) == nil)
{
pActiveDoc = ((Ptr) activeInstrsPtr) + (pActiveEvent->message & LO3BYTES);
CopyWDToCurProc(pActiveDoc->vRefNum, &wdpbRec);
}
else
{
pActiveDoc = nil;
if (FileIDToAppFile((AETFDescriptor *) (msgBlk->addrOfMsg), &appFile, &theVol, &theDir) == noErr)
{
NextListParam((AETFDescriptor **) &msgBlk->addrOfMsg);
wdpbRec.ioNamePtr = nil;
wdpbRec.ioVRefNum = theVol;
wdpbRec.ioWDProcID = 0;
wdpbRec.ioWDDirID = theDir;
wdpbRec.ioCompletion = nil;
(void) PBOpenWD(&wdpbRec, SyncHFS);
appFile.vRefNum = wdpbRec.ioVRefNum;
pActiveDoc = &appFile;
}
}
pSFReply->vRefNum = wdpbRec.ioVRefNum;
if ( (pActiveDoc != nil)
&& (InTypeList(pActiveDoc->fType, pSFTypeList, numTypes) && AcceptedByFileFilter(pActiveDoc, fileFilterFnc)) )
{
/* Call word dialog hook to clear r/o flag */
if (dlgHook != nil)
{
/* Fake out word <= 3.01 to not make the doc r/o by giving it an extra init call */
pDialog = GetNewDialog(dlgID, nil, (Ptr)(-1));
if (pDialog)
{
(void) CurrentA5SimpleSetup();
CALL_FNC_PTR(DialogHookPtr, dlgHook, (-1, pDialog));
(void) ProcessMgrA5SimpleSetup();
DisposDialog(pDialog);
}
}
pSFReply->good = true;
pSFReply->fType = pActiveDoc->fType;
pSFReply->version = pActiveDoc->versNum;
if ((strLengthPlus1 = Length(&(pActiveDoc->fName)) + 1) > (MAX_SF_FNAME_LEN + 1))
strLengthPlus1 = MAX_SF_FNAME_LEN + 1;
BlockMove(&pActiveDoc->fName, &pSFReply->fName, strLengthPlus1);
}
else
{
/* Tell sawdust-head that the PACK 3 failed */
pSFReply->good = false;
/* Shouldn't cancel, and needn't close WD, if the file translation failed */
if (pActiveDoc != nil)
{
/* Close the WD, if we opened it */
if (wdpbRec.ioWDCreated != 0)
PBCloseWD(&wdpbRec, SyncHFS);
/* Force back to offending instruction, then cancel */
activeInstrsPtr->offset -= sizeof(EventRecord);
CancelSwitchWithError();
}
}
}
HUnlock(activeInstrsHdl);
}
A5SimpleRestore(olda5);
return(isForcedOpen);
}