Back to index

lightning-sunbird  0.9+nobinonly
InstallCleanupMac.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Don Bragg <dbragg@netscape.com>
00024  *   Samir Gehani <sgehani@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include <stdio.h>
00041 #include <string.h>
00042 #include <unistd.h>
00043 #include <MacTypes.h>
00044 #include "MoreFiles.h"
00045 #include "MoreFilesExtras.h"
00046 #include "FullPath.h"  
00047 #include <AppleEvents.h>
00048 #include <Gestalt.h>
00049 #include <TextUtils.h>
00050 #include <Folders.h>
00051 #include <Processes.h>
00052 #include <Resources.h>
00053 #include <Aliases.h>
00054 
00055 #include "InstallCleanup.h"
00056 #include "InstallCleanupDefines.h"
00057 
00058 #define kSleepMax 60  // sleep 1 second
00059 
00060 Boolean gAppleEventsFlag, gQuitFlag;
00061 long gSleepVal;
00062 
00063 
00064 int   strcasecmp(const char *str1, const char *str2);
00065 OSErr GetFSSpecFromPath(char *aPath, FSSpec *aSpec);
00066 void  my_c2pstrcpy(Str255 aDstPStr, const char *aSrcCStr);
00067 OSErr GetCWD(short *aVRefNum, long *aDirID);
00068 OSErr GetCleanupReg(FSSpec *aCleanupReg);
00069 
00070 int strcasecmp(const char *str1, const char *str2)
00071 {
00072     char    currentChar1, currentChar2;
00073 
00074     while (1) {
00075     
00076         currentChar1 = *str1;
00077         currentChar2 = *str2;
00078         
00079         if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
00080             currentChar1 += ('A' - 'a');
00081         
00082         if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
00083             currentChar2 += ('A' - 'a');
00084                 
00085         if (currentChar1 == '\0')
00086             break;
00087     
00088         if (currentChar1 != currentChar2)
00089             return currentChar1 - currentChar2;
00090             
00091         str1++;
00092         str2++;
00093     
00094     }
00095     
00096     return currentChar1 - currentChar2;
00097 }
00098 
00099 OSErr GetFSSpecFromPath(const char *aPath, FSSpec *aSpec)
00100 {
00101     if (!aPath || !aSpec)
00102         return paramErr;
00103         
00104     // 1> verify path is not an empty string
00105     // 2> verify path has leaf
00106     // 3> verify path does not start with leading ':'
00107     
00108     if ((!*aPath) || 
00109        (*(aPath + strlen(aPath) - 1) == ':') ||
00110        (*aPath == ':'))
00111     {
00112        return paramErr;
00113     }
00114     
00115     // path is kosher: get FSSpec for it
00116     return FSpLocationFromFullPath(strlen(aPath), (const void *) aPath, aSpec);
00117 }
00118 
00119 void
00120 my_c2pstrcpy(Str255 aDstPStr, const char *aSrcCStr)
00121 {
00122     if (!aSrcCStr)
00123         return;
00124     
00125     memcpy(&aDstPStr[1], aSrcCStr, strlen(aSrcCStr) > 255 ? 255 : strlen(aSrcCStr));
00126     aDstPStr[0] = strlen(aSrcCStr);
00127 }
00128 
00129 OSErr
00130 GetCWD(short *aVRefNum, long *aDirID)
00131 {
00132     OSErr               err = noErr;
00133     ProcessSerialNumber psn;
00134     ProcessInfoRec      pInfo;
00135     FSSpec              tmp;
00136         
00137     if (!aVRefNum || !aDirID)
00138         return paramErr;
00139     
00140     *aVRefNum = 0;
00141     *aDirID = 0;
00142     
00143     /* get cwd based on curr ps info */
00144     if (!(err = GetCurrentProcess(&psn))) 
00145     {
00146         pInfo.processName = nil;
00147         pInfo.processAppSpec = &tmp;
00148         pInfo.processInfoLength = (sizeof(ProcessInfoRec));
00149              
00150         if(!(err = GetProcessInformation(&psn, &pInfo)))
00151         {   
00152             *aVRefNum = pInfo.processAppSpec->vRefNum;
00153             *aDirID = pInfo.processAppSpec->parID; 
00154         }
00155     }
00156       
00157     return err;
00158 }
00159 
00160 OSErr
00161 GetCleanupReg(FSSpec *aCleanupReg)
00162 {
00163     OSErr err = noErr;
00164     short efVRefNum = 0;
00165     long efDirID = 0;
00166     
00167     if (!aCleanupReg)
00168         return paramErr;
00169         
00170     err = GetCWD(&efVRefNum, &efDirID);
00171     if (err == noErr)
00172     {
00173         Str255 pCleanupReg;
00174         my_c2pstrcpy(pCleanupReg, CLEANUP_REGISTRY);
00175         err = FSMakeFSSpec(efVRefNum, efDirID, pCleanupReg, aCleanupReg);
00176     }
00177     
00178     return err;
00179 }
00180 
00181 
00182 #pragma mark -
00183 
00184 //----------------------------------------------------------------------------
00185 // Native Mac file deletion function
00186 //----------------------------------------------------------------------------
00187 int NativeDeleteFile(const char* aFileToDelete)
00188 {
00189     OSErr err;
00190     FSSpec delSpec;
00191     
00192     if (!aFileToDelete)
00193         return DONE;
00194         
00195     // stat the file
00196     err = GetFSSpecFromPath(aFileToDelete, &delSpec);
00197     if (err != noErr)
00198     {
00199         // return fine if it doesn't exist
00200         return DONE;
00201     }
00202         
00203     // else try to delete it
00204     err = FSpDelete(&delSpec);
00205     if (err != noErr)
00206     {
00207         // tell user to try again later if deletion failed
00208         return TRY_LATER;
00209     }
00210 
00211     return DONE;
00212 }
00213 
00214 //----------------------------------------------------------------------------
00215 // Native Mac file replacement function
00216 //----------------------------------------------------------------------------
00217 int NativeReplaceFile(const char* aReplacementFile, const char* aDoomedFile )
00218 {
00219     OSErr err;
00220     FSSpec replSpec, doomSpec, tgtDirSpec;
00221     long dirID;
00222     Boolean isDir;
00223     
00224     if (!aReplacementFile || !aDoomedFile)
00225         return DONE;
00226         
00227     err = GetFSSpecFromPath(aReplacementFile, &replSpec);
00228     if (err != noErr)
00229         return DONE;
00230                       
00231     // stat replacement file
00232     err = FSpGetDirectoryID(&replSpec, &dirID, &isDir);
00233     if (err != noErr || isDir)
00234     {
00235         // return fine if it doesn't exist
00236         return DONE;
00237     }
00238         
00239     // check if the replacement file and doomed file are the same
00240     if (strcasecmp(aReplacementFile, aDoomedFile) == 0)
00241     {
00242         // return fine if they are the same
00243         return DONE;
00244     }
00245         
00246     // try and delete doomed file (NOTE: this call also stats)
00247     err = GetFSSpecFromPath(aDoomedFile, &doomSpec); 
00248     if (err == noErr)
00249     { 
00250         // (will even try to delete a dir with this name)
00251         err = FSpDelete(&doomSpec);
00252         
00253         // if deletion failed tell user to try again later
00254         if (err != noErr)
00255             return TRY_LATER;
00256     }
00257     
00258     // get the target dir spec (parent directory of doomed file)
00259     err = FSMakeFSSpec(doomSpec.vRefNum, doomSpec.parID, "\p", &tgtDirSpec);
00260     if (err == noErr)
00261     {
00262         // now try and move replacment file to path of doomed file
00263         err = FSpMoveRename(&replSpec, &tgtDirSpec, doomSpec.name);
00264         if (err != noErr)
00265         {
00266             // if move failed tell user to try agian later
00267             return TRY_LATER;
00268         }
00269     }
00270         
00271     return DONE;
00272 }
00273 
00274 
00275 #pragma mark -
00276 
00277 //----------------------------------------------------------------------------
00278 // Routines for recovery on reboot
00279 //----------------------------------------------------------------------------
00280 OSErr
00281 GetProgramSpec(FSSpecPtr aProgSpec)
00282 {
00283        OSErr                       err = noErr;
00284        ProcessSerialNumber  psn;
00285        ProcessInfoRec              pInfo;
00286        
00287        if (!aProgSpec)
00288            return paramErr;
00289            
00290        /* get cwd based on curr ps info */
00291        if (!(err = GetCurrentProcess(&psn))) 
00292        {
00293               pInfo.processName = nil;
00294               pInfo.processAppSpec = aProgSpec;
00295               pInfo.processInfoLength = (sizeof(ProcessInfoRec));
00296               
00297               err = GetProcessInformation(&psn, &pInfo);
00298        }
00299        
00300        return err;
00301 }
00302 
00303 void
00304 PutAliasInStartupItems(FSSpecPtr aAlias)
00305 {
00306     OSErr err;
00307     FSSpec fsProg, fsAlias;
00308     long strtDirID = 0;
00309     short strtVRefNum = 0;
00310     FInfo info;
00311     AliasHandle aliasH;
00312 
00313     if (!aAlias)
00314         return;
00315         
00316     // find cwd
00317     err = GetProgramSpec(&fsProg);
00318     if (err != noErr)
00319         return;  // fail silently
00320      
00321     // get startup items folder
00322     err = FindFolder(kOnSystemDisk, kStartupFolderType, kCreateFolder, 
00323                      &strtVRefNum, &strtDirID);
00324     if (err != noErr)
00325         return;
00326              
00327     // check that an alias to ourselves doesn't already
00328     // exist in the Startup Items folder
00329     err = FSMakeFSSpec(strtVRefNum, strtDirID, fsProg.name, &fsAlias);
00330     if (err == noErr)
00331     {
00332         // one's already there; not sure it's us so delete and recreate
00333         // (being super paranoid; but hey it's a mac)
00334         err = FSpDelete(&fsAlias);
00335         if (err != noErr)
00336             return;  // fail silently
00337     }
00338       
00339     // create the alias file
00340     err = NewAliasMinimal(&fsProg, &aliasH);
00341     if (err != noErr) 
00342         return;
00343         
00344     FSpGetFInfo(&fsProg, &info);
00345     FSpCreateResFile(&fsAlias, info.fdCreator, info.fdType, smRoman);
00346     short refNum = FSpOpenResFile(&fsAlias, fsRdWrPerm);
00347     if (refNum != -1)
00348     {
00349         UseResFile(refNum);
00350         AddResource((Handle)aliasH, rAliasType, 0, fsAlias.name);
00351         ReleaseResource((Handle)aliasH);
00352         UpdateResFile(refNum);
00353         CloseResFile(refNum);
00354     }
00355     else
00356     {
00357         ReleaseResource((Handle)aliasH);
00358         FSpDelete(&fsAlias);
00359         return;  // non-fatal error
00360     }
00361 
00362     // mark newly created file as an alias file
00363     FSpGetFInfo(&fsAlias, &info);
00364     info.fdFlags |= kIsAlias;
00365     FSpSetFInfo(&fsAlias, &info);    
00366     
00367     *aAlias = fsAlias;
00368 }
00369 
00370 void
00371 RemoveAliasFromStartupItems(FSSpecPtr aAlias)
00372 {
00373     // try to delete the alias
00374     FSpDelete(aAlias);
00375 }
00376 
00377 
00378 #pragma mark -
00379 
00380 //----------------------------------------------------------------------------
00381 // Apple event handlers to be installed
00382 //----------------------------------------------------------------------------
00383 
00384 static pascal OSErr DoAEOpenApplication(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
00385 {
00386 #pragma unused (theAppleEvent, replyAppleEvent, refCon)
00387     return noErr;
00388 }
00389 
00390 static pascal OSErr DoAEOpenDocuments(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
00391 {
00392 #pragma unused (theAppleEvent, replyAppleEvent, refCon)
00393     return errAEEventNotHandled;
00394 }
00395 
00396 static pascal OSErr DoAEPrintDocuments(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
00397 {
00398 #pragma unused (theAppleEvent, replyAppleEvent, refCon)
00399     return errAEEventNotHandled;
00400 }
00401 
00402 static pascal OSErr DoAEQuitApplication(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
00403 {
00404 #pragma unused (theAppleEvent, replyAppleEvent, refCon)
00405     gQuitFlag = true;
00406     return noErr;
00407 }
00408 
00409 
00410 //----------------------------------------------------------------------------
00411 // install Apple event handlers
00412 //----------------------------------------------------------------------------
00413 
00414 static void InitAppleEventsStuff(void)
00415 {
00416     OSErr retCode;
00417 
00418     if (gAppleEventsFlag) {
00419 
00420         retCode = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
00421                     NewAEEventHandlerUPP(DoAEOpenApplication), 0, false);
00422 
00423         if (retCode == noErr)
00424             retCode = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
00425                     NewAEEventHandlerUPP(DoAEOpenDocuments), 0, false);
00426 
00427         if (retCode == noErr)
00428             retCode = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
00429                     NewAEEventHandlerUPP(DoAEPrintDocuments), 0, false);
00430         if (retCode == noErr)
00431             retCode = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
00432                     NewAEEventHandlerUPP(DoAEQuitApplication), 0, false);
00433 
00434         if (retCode != noErr) DebugStr("\pInstall event handler failed");
00435         // a better way to indicate an error is to post a notification
00436     }
00437 }
00438 
00439 
00440 //----------------------------------------------------------------------------
00441 // high-level event dispatching
00442 //----------------------------------------------------------------------------
00443 
00444 static void DoHighLevelEvent(EventRecord * theEventRecPtr)
00445 {
00446     (void) AEProcessAppleEvent(theEventRecPtr);
00447 }
00448 
00449 
00450 #pragma mark -
00451 
00452 void main(void)
00453 {
00454     OSErr retCode;
00455     long gestResponse;
00456     FSSpec aliasToSelf;
00457     FSSpec fsCleanupReg;
00458 
00459     EventRecord mainEventRec;
00460     Boolean eventFlag, bDone = false, bHaveCleanupReg = false;
00461     
00462     HREG reg;
00463     int rv = DONE;
00464 
00465 #if !TARGET_CARBON
00466     // initialize QuickDraw globals
00467     InitGraf(&qd.thePort);
00468 #endif
00469 
00470     // initialize application globals
00471     gQuitFlag = false;
00472     gSleepVal = kSleepMax;
00473 
00474     // is the Apple Event Manager available?
00475     retCode = Gestalt(gestaltAppleEventsAttr, &gestResponse);
00476     if (retCode == noErr &&
00477         (gestResponse & (1 << gestaltAppleEventsPresent)) != 0)
00478         gAppleEventsFlag = true;
00479     else gAppleEventsFlag = false;
00480 
00481     // install Apple event handlers
00482     InitAppleEventsStuff();
00483 
00484     // put an alias to ourselves in the Startup Items folder
00485     // so that if we are shutdown before finishing we do our 
00486     // tasks at startup
00487     FSMakeFSSpec(0, 0, "\p", &aliasToSelf);  // initialize
00488     PutAliasInStartupItems(&aliasToSelf);
00489     
00490     if ( REGERR_OK == NR_StartupRegistry() )
00491     {
00492         char *regName = "";
00493         Boolean regNameAllocd = false;
00494         Handle pathH = 0;
00495         short pathLen = 0;
00496         
00497         // check if XPICleanup data file exists
00498         retCode = GetCleanupReg(&fsCleanupReg);
00499         if (retCode == noErr)
00500         {
00501             bHaveCleanupReg = true;
00502             
00503             // get full path to give to libreg open routine
00504             retCode = FSpGetFullPath(&fsCleanupReg, &pathLen, &pathH);
00505             if (retCode == noErr && pathH)
00506             {
00507                 HLock(pathH);
00508                 if (*pathH)
00509                 {
00510                     regName = (char *) malloc(sizeof(char) * (pathLen + 1));
00511                     if (regName)
00512                         regNameAllocd = true;
00513                     else
00514                         retCode = memFullErr;
00515                     strncpy(regName, *pathH, pathLen);
00516                     *(regName + pathLen) = 0;
00517                 }
00518                 HUnlock(pathH);
00519                 DisposeHandle(pathH);
00520             }
00521         }
00522             
00523         if ( (retCode == noErr) && (REGERR_OK == NR_RegOpen(regName, &reg)) )
00524         {
00525             // main event loop
00526 
00527             while (!gQuitFlag)
00528             {
00529                 eventFlag = WaitNextEvent(everyEvent, &mainEventRec, gSleepVal, nil);
00530 
00531                 if (mainEventRec.what == kHighLevelEvent)
00532                     DoHighLevelEvent(&mainEventRec);
00533 
00534                 rv = PerformScheduledTasks(reg);
00535                 if (rv == DONE)
00536                 {
00537                     bDone = true;
00538                     gQuitFlag = true;
00539                 }
00540             }
00541             NR_RegClose(&reg);
00542             NR_ShutdownRegistry();
00543         }
00544         
00545         if (regNameAllocd)
00546             free(regName);      
00547     }
00548     
00549     // clean up the alias to ouselves since we have 
00550     // completed our tasks successfully
00551     if (bDone)
00552     {
00553         if (bHaveCleanupReg)
00554             FSpDelete(&fsCleanupReg);
00555         RemoveAliasFromStartupItems(&aliasToSelf);
00556     }
00557 }
00558