PutAwayOneVolume.c

/*
    File:       PutAwayOneVolume.c
    
    Description:
 
    Author:     PG
 
    Copyright:  Copyright: © 1996-1999 by Apple Computer, Inc.
                all rights reserved.
    
    Disclaimer: You may incorporate this sample code into your applications without
                restriction, though the sample code has been provided "AS IS" and the
                responsibility for its operation is 100% yours.  However, what you are
                not permitted to do is to redistribute the source as "DSC Sample Code"
                after having made changes. If you're going to re-distribute the source,
                we require that you make it clear in the source that the code was
                descended from Apple Sample Code, but that you've made changes.
    
    Change History (most recent first):
                6/25/99     Updated for Metrowerks Codewarror Pro 2.1(KG)
                03/21/96    Created(PG
 
*/
#define OLDROUTINELOCATIONS     0
#define OLDROUTINENAMES         0
#define SystemSevenOrLater      1
 
#ifndef __DIALOGS__
#   include <Dialogs.h>
#endif
 
#ifndef __AEREGISTRY__
#   include <AERegistry.h>
#endif
 
#ifndef __APPLEEVENTS__
#   include <AppleEvents.h>
#endif
 
#ifndef __MOREFILESEXTRAS__
#   include "MoreFilesExtras.h"
#endif
 
#ifndef __ALIASES__
#   include <Aliases.h>
#endif
 
#ifndef __FOLDERS__
#   include <Folders.h>
#endif
 
#include "PutAwayOneVolume.h"
 
#if GENERATINGCFM
 
#ifndef __TRAPS__
#   include <Traps.h>
#endif
 
pascal OSErr ReleaseFolder (short vRefNum, OSType folderType)
{
    const unsigned long selector = 0xB;
 
    enum
    {
        uppReleaseFolderInfo = kD0DispatchedPascalStackBased
            | RESULT_SIZE (SIZE_CODE (sizeof(OSErr)))
            | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE (SIZE_CODE (sizeof (selector)))
            | DISPATCHED_STACK_ROUTINE_PARAMETER (1,SIZE_CODE (sizeof (vRefNum)))
            | DISPATCHED_STACK_ROUTINE_PARAMETER (2,SIZE_CODE (sizeof (folderType)))
    };
 
    return CallUniversalProc (GetToolTrapAddress (_AliasDispatch), uppReleaseFolderInfo, selector, vRefNum, folderType);
}
 
#endif
 
static pascal OSErr BuildAppleEvent (short vRefNum, AppleEvent *event)
{
    OSErr err = noErr;
 
    FSSpecPtr fssP = (FSSpecPtr) NewPtr (sizeof (*fssP));
    if (!(err = MemError ( )))
    {
        if (!(err = FSMakeFSSpec (vRefNum, fsRtDirID, nil, fssP)))
        {
            AliasHandle aliasH;
        
            if (!(err = NewAlias (nil, fssP, &aliasH)))
            {
                HLockHi ((Handle) aliasH);
                if (!(err = MemError ( )))
                {
                    Size size = GetHandleSize ((Handle) aliasH);
                    if (!(err = MemError ( )))
                    {
                        if (!(err = AEPutParamPtr (event,keyDirectObject,typeAlias,*aliasH,size)))
                        {
                            AEDescList aeDescList;
                        
                            if (!(err = AECreateList (nil,0,false,&aeDescList)))
                            {
                                if (!(err = AEPutPtr (&aeDescList,1,typeAlias,*aliasH,size)))
                                    err = AEPutParamDesc (event,keySelection,&aeDescList);
                        
                                AEDisposeDesc (&aeDescList);
                            }
                        }
                    }
                }
                DisposeHandle ((Handle) aliasH);
                if (!err) err = MemError ( );
            }
        }
        DisposePtr ((Ptr) fssP);
        if (!err) err = MemError ( );
    }
 
    return err;
}
 
static pascal OSErr PutAwayOneVolumeByAppleEvent (short vRefNum, OSType finderLikeProcess)
{
    OSErr err = noErr;
 
    AEAddressDesc address;
 
    if (!(err = AECreateDesc (typeApplSignature, &finderLikeProcess, sizeof (finderLikeProcess), &address)))
    {
        AppleEvent event;
 
        if (!(err = AECreateAppleEvent (kAEFinderEvents,kAEPutAwaySelection,&address,kAutoGenerateReturnID,kAnyTransactionID,&event)))
        {
            if (!(err = BuildAppleEvent (vRefNum, &event)))
            {
                AppleEvent reply;
                err = AESend (&event,&reply,kAENoReply,kAENormalPriority,kAEDefaultTimeout,nil,nil);
            }
 
            AEDisposeDesc (&event);
        }
 
        AEDisposeDesc (&address);
    }
 
    return err;
}
 
static pascal Boolean ConfirmEmptyTrash (short vRefNum, Boolean *confirmed)
{
    OSErr       err     = noErr;
    DialogRef   dlgRef  = nil;
    
    *confirmed = false;
 
    dlgRef = GetNewDialog (128,nil,(DialogRef)-1);
    if (dlgRef && !SetDialogDefaultItem (dlgRef,ok))
    {
        FSSpecPtr fssP = (FSSpecPtr) NewPtr (sizeof (FSSpec));
 
        if (!(err = MemError ( )))
        {
            if (!FSMakeFSSpec (vRefNum,fsRtDirID,nil,fssP))
            {
                short itemHit;
 
                ParamText (fssP->name,nil,nil,nil);
                ShowWindow (dlgRef);
                ModalDialog (nil,&itemHit);
                DisposeDialog (dlgRef);
        
                if (itemHit == ok)
                    *confirmed = true;
            }
 
            DisposePtr ((Ptr) fssP);
            if (!err) err = MemError ( );
        }
    }
 
    return err;
}
 
static pascal OSErr CountFilesInDir (short vRefNum, long dirID, unsigned short *ioDrNmFls)
{
    OSErr err = noErr;
 
    CInfoPBPtr cipbp = (CInfoPBPtr) NewPtrClear (sizeof (CInfoPBRec));
 
    if (!(err = MemError ( )))
    {
        cipbp->dirInfo.ioVRefNum    = vRefNum;
        cipbp->dirInfo.ioDrDirID    = dirID;
        cipbp->dirInfo.ioFDirIndex  = -1; // ignore ioNamePtr
 
        if (!(err = PBGetCatInfoSync (cipbp)))
            *ioDrNmFls = cipbp->dirInfo.ioDrNmFls;
 
        DisposePtr ((Ptr) cipbp);
        if (!err) err = MemError ( );
    }
 
    return err;
}
 
static pascal OSErr EmptyTrash (short vRefNum)
{
    OSErr   err = noErr;
 
    short   foundVRefNum;
    long    foundDirID;
 
    err = FindFolder (vRefNum,kTrashFolderType,false,&foundVRefNum,&foundDirID);
 
    if (err == fnfErr)  // if the trash ain't there,
        err = noErr;    // consider it empty
    else if (!err)
    {
        unsigned short ioDrNmFls;
 
        if (!(err = CountFilesInDir (foundVRefNum,foundDirID,&ioDrNmFls)))
        {
            if (ioDrNmFls)
            {
                Boolean confirmed;
        
                if (!(err = ConfirmEmptyTrash (foundVRefNum,&confirmed)))
                {
                    if (!confirmed)
                        err = userCanceledErr;
                    else
                    {
                        FSSpecPtr fssP = (FSSpecPtr) NewPtr (sizeof (FSSpec));
                
                        if (!(err = MemError ( )))
                        {
                            if (!(err = FSMakeFSSpec (foundVRefNum,foundDirID,nil,fssP)))
                                err = DeleteDirectory (fssP->vRefNum,fssP->parID,fssP->name);
                                // DeleteDirectory is from MoreFiles
 
                            DisposePtr ((Ptr) fssP);
                            if (!err) err = MemError ( );
                        }
                    }
                }
            }
 
            if (!err)
                err = ReleaseFolder (foundVRefNum,kTrashFolderType);
        }
    }
 
    return err;
}
 
pascal OSErr PutAwayOneVolume (short vRefNum, OSType finderLikeProcess)
{
    //
    //  Administrates task of unmounting a volume. If 'finderLikeProcess' is zero,
    //  will attempt to unmount with internal code. (Internal code doesn't yet
    //  work on PowerPC because there's no glue for ReleaseFolder.) If 'finderLikeProcess'
    //  is non-zero, will send AppleEvent which conforms to the Finder Suite's
    //  "put away" spec to that process. For volumes, "put away" means "unmount".
    //
 
    OSErr err = noErr;
 
    if (finderLikeProcess)
        err = PutAwayOneVolumeByAppleEvent (vRefNum,finderLikeProcess);
    else if (!(err = EmptyTrash (vRefNum)))
        err = UnmountAndEject (nil,vRefNum);
        // UnmountAndEject is from MoreFiles
 
    return err;
}