home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / APLocation / Sources / Utilities.c < prev    next >
Encoding:
Text File  |  2001-06-23  |  14.7 KB  |  574 lines

  1. /*
  2.      File:        Utilities.c
  3.  
  4.      Contains:    Location Manager SDK Sample Module handy routines
  5.  
  6.      Version:    ALM SDK 2.0
  7.                  Package:    Location Manager SDK 2.0
  8.  
  9.      Copyright:    © 1996-1997 by Apple Computer, Inc.
  10.                  All rights reserved.
  11.  
  12.      Bugs?:        Please include the the file and version information (from above) with
  13.                  the problem description.  Developers belonging to one of the Apple
  14.                  developer programs can submit bug reports to:
  15.  
  16.                      devsupport@apple.com
  17.  
  18. */
  19.  
  20. // ------------------------------------------------------------------------------------------------- 
  21.  
  22. // Module Include...
  23.  
  24. #include "Utilities.h"
  25.  
  26. // Project Includes...
  27.  
  28. #include "APLocation.h"
  29.  
  30. // Connectix includes
  31.  
  32. #include "MacOS_ConnectixUtils.h"
  33. #include "MacOS_UAppleEvents.h"
  34.  
  35. // MacOS Includes...
  36.  
  37. #include <ASRegistry.h>
  38. #include <FSM.h>
  39. #include <Folders.h>
  40. #include <Gestalt.h>
  41. #include <LowMem.h>
  42. #include <PLStringFuncs.h>
  43. #include <Resources.h>
  44. #include <Script.h>
  45. #include <Timer.h>
  46.  
  47. // ANSI Includes...
  48.  
  49. #include <string.h>
  50. #include <stdio.h>
  51.  
  52. // ------------------------------------------------------------------------------------------------- 
  53.  
  54. // Readability Constants...
  55.  
  56. #define        kInvalidRefNum                        (-1)
  57. #define        kUseSetting                            false
  58. #define        kReadSetting                        true
  59. #define        kNoIdleProc                            NULL
  60. #define        kNoFilterProc                        NULL
  61. #define        kTimeToQuit                            (10*60)        // 10 seconds to quit...    
  62. #define        kDontUseIndex                        0
  63. #define        kNoFileName                            "\p"
  64. #define        kUseVRefNumOnly                        NULL
  65. #define        kExtractFileFlagsFromFinder            0
  66. #define        kGetMostRecentlyCreatedMatch        0
  67.  
  68. // Expressive Macros...
  69.  
  70. #define        ShareTime()                { EventRecord e; WaitNextEvent (0, &e, 1, NULL); }
  71. #define        EmptyAEDesc(desc)        { desc.descriptorType = typeNull; \
  72.                                             desc.dataHandle = NULL; }
  73. #define     SetFirstProcess(psn)    { psn.highLongOfPSN = 0; \
  74.                                             psn.lowLongOfPSN = kNoProcess; }
  75.  
  76. // ------------------------------------------------------------------------------------------------- 
  77.  
  78. // Local prototypes...
  79.  
  80. static OSErr
  81. SetPower(Boolean inPowerOn);
  82.  
  83. static OSErr
  84. JoinNetwork(ConstStr255Param inNetwork);
  85.  
  86. static OSErr
  87. SendQuitApplication (Boolean* wasOpen, OSType creator);
  88.     // Send a "quit" AppleEvent to the application whose creator is given...
  89.  
  90. static OSErr
  91. LaunchIt (ConstFSSpecPtr theApplication, LaunchFlags theFlags);
  92.     // Launch the specified application with the specified flags...
  93.  
  94. static Boolean
  95. FindProcessByCreator (ProcessSerialNumber* psn, OSType creator);
  96.     // Given a creator code, return the process serial number of the first matching process...
  97.     
  98. static Boolean
  99. ProcessManagerAvailable (void);
  100.     // Good way to tell if it's INIT time...
  101.     
  102. static Boolean
  103. ProcessBecameInvalid (ProcessSerialNumber* psn, UInt32 timeoutInTicks);
  104.     // Little routine to wait for a process to quit (since we can't wait for a reply
  105.     // event)...
  106.     
  107. // ------------------------------------------------------------------------------------------------- 
  108.  
  109. static void
  110. WaitTicks(
  111.     long    inTicks)
  112. {
  113.     long    startTime = TickCount();
  114.     while (TickCount() < startTime + inTicks)
  115.         ShareTime();
  116. }
  117.  
  118.  
  119. /*------------------------------------------------------------------
  120.     UseSetting
  121. ------------------------------------------------------------------*/
  122.  
  123. extern OSErr
  124. UseSetting(
  125.     GlobalsHandle        inGlobals,
  126.     APSettingHandle        inOldSetting,
  127.     APSettingHandle        inNewSetting,
  128.     ALMRebootFlags *    inFlags)
  129. {
  130.     OSErr    err;
  131.     
  132.     // fix me - verify settings version
  133.     
  134.     // Launch "AirPort Scripting" and join the specified network.
  135.     err = LaunchAPScripting();
  136.     require(err == noErr, LaunchAPScriptingFailed);
  137.     
  138.     check((**inNewSetting).version == 'nheg');
  139.     
  140.     if ((**inOldSetting).powerOn != (**inNewSetting).powerOn)
  141.     {
  142.         err = SetPower((**inNewSetting).powerOn);
  143.         require(err == noErr, SetPowerFailed);
  144.         
  145.         if ((**inNewSetting).powerOn)
  146.         {
  147.             // This is ugly, but "AirPort Scripting" is uglier.
  148.             WaitTicks(5 * 60);
  149.         }
  150.     }
  151.     
  152.     if ((**inNewSetting).powerOn)
  153.     {
  154.         err = JoinNetwork((**inNewSetting).network);
  155.         require(err == noErr, JoinNetworkFailed);
  156.         
  157.         // Let things settle down before moving on.
  158.         WaitTicks(60);
  159.     }
  160.     
  161. LaunchAPScriptingFailed:
  162. SetPowerFailed:
  163. JoinNetworkFailed:
  164.     return err;
  165. }
  166.  
  167.  
  168. /*------------------------------------------------------------------
  169.     ReadSetting
  170. ------------------------------------------------------------------*/
  171.  
  172. OSErr
  173. ReadSetting(
  174.     GlobalsHandle        inGlobals,
  175.     APSettingHandle        inSetting)
  176. {
  177.     OSErr    err;
  178.     
  179.     LaunchAPScripting();
  180.     
  181.     SetHandleSize(reinterpret_cast<Handle>(inSetting), sizeof(APSettingRec));
  182.     
  183.     // Save our cookie/version.
  184.     (**inSetting).version = 'nheg';
  185.     
  186.     AEAppleEvent    getEvent(kAECoreSuite, kAEGetData, '1wse');
  187.     AEAppleEvent    reply;
  188.     AEDescriptor    cardDesc;
  189.     
  190.     // Create descriptor for "card 1".
  191.     err = ::CreateIndexObjectSpecifier('cair', &kAENullDescriptor, 1, &cardDesc);
  192.     require(err == noErr, FatalError);
  193.     
  194.     // Find out if the card is on.
  195.     {
  196.         AEDescriptor        powerDesc;
  197.         Boolean                powerOn;
  198.         
  199.         // Create descriptor for "power of card 1".
  200.         err = CreatePropertyObjectSpecifier(cProperty, &cardDesc, '42po', &powerDesc);
  201.         require(err == noErr, FatalError);
  202.         
  203.         err = getEvent.PutParameterDesc(keyDirectObject, powerDesc);
  204.         require(err == noErr, FatalError);
  205.         
  206.         err = getEvent.Send(reply, kAEWaitReply);
  207.         require(err == noErr, FatalError);
  208.         
  209.         err = reply.GetParameter(keyDirectObject, (**inSetting).powerOn);
  210.         require_action(err == noErr, GetParameterFailed, err = GetAEErrorNumber(&reply););
  211.     }
  212.     
  213.     // If the power was on, get the network name.
  214.     if ((**inSetting).powerOn)
  215.     {
  216.         AEDescriptor        networkDesc;
  217.         AEDescriptorRecord    networkRec;
  218.         
  219.         // Create descriptor for "network of card 1"
  220.         err = ::CreatePropertyObjectSpecifier(cProperty, &cardDesc, 'cwir', &networkDesc);
  221.         require(err == noErr, FatalError);
  222.         
  223.         err = getEvent.PutParameterDesc(keyDirectObject, networkDesc);
  224.         require(err == noErr, FatalError);
  225.         
  226.         err = getEvent.Send(reply, kAEWaitReply);
  227.         require(err == noErr, FatalError);
  228.         
  229.         err = reply.GetParameterDesc(keyDirectObject, typeAERecord, networkRec);
  230.         require(err == noErr, FatalError);
  231.         
  232.         // Extract the name from the returned network object.
  233.         err = networkRec.GetPStringKey('42nm', (**inSetting).network);
  234.         require_action(err == noErr, GetPStringKeyFailed, err = GetAEErrorNumber(&reply););
  235.     }
  236.     
  237. FatalError:
  238. GetParameterFailed:
  239. GetPStringKeyFailed:
  240.     return err;
  241. }
  242.  
  243.  
  244. // ------------------------------------------------------------------------------------------------- 
  245.  
  246. extern void
  247. InsParamStr (StringPtr matchThis, StringPtr replaceWithThis, StringPtr replaceInThis) {
  248.  
  249.     UInt8        matchLen        = StrLength (matchThis);
  250.     UInt8        replaceLen        = StrLength (replaceWithThis);
  251.     UInt8        replaceInLen    = StrLength (replaceInThis);
  252.     Ptr            matchPtr;
  253.     Str255        tempStr;
  254.  
  255.     matchPtr = PLstrstr (replaceInThis, matchThis);
  256.     PLstrcpy (tempStr, replaceInThis);
  257.  
  258.     if (matchPtr != NULL) {
  259.     
  260.         UInt8        matchPos    = (UInt32) matchPtr - (UInt32) replaceInThis;
  261.         UInt8        contPos        = matchPos + matchLen;
  262.         UInt8        frontLen    = matchPos - 1;
  263.         UInt8        backLen        = replaceInLen - frontLen - matchLen;
  264.         
  265.         BlockMoveData (&replaceWithThis[1], &replaceInThis[matchPos], replaceLen);
  266.         BlockMoveData (&tempStr[contPos], &replaceInThis[frontLen + replaceLen + 1], backLen);
  267.         replaceInThis[0] = ((UInt32) replaceInLen - (UInt32) matchLen + (UInt32) replaceLen);
  268.         
  269.     } // if
  270.  
  271. } // InsParamStr
  272.  
  273. // ------------------------------------------------------------------------------------------------- 
  274.  
  275. /*------------------------------------------------------------------
  276.     SetPower
  277. ------------------------------------------------------------------*/
  278.  
  279. OSErr
  280. SetPower(
  281.     Boolean    inPowerOn)
  282. {
  283.     OSErr    err = noErr;
  284.     
  285.     Boolean            powerOn = inPowerOn;
  286.     AEAppleEvent    setEvent(kAECoreSuite, kAESetData, '1wse');
  287.     AEDescriptor    cardDesc;
  288.     AEDescriptor    powerDesc;
  289.     AEDescriptor    powerOnDesc(inPowerOn ? typeTrue : typeFalse, NULL, 0);
  290.     
  291.     // Create the descriptor for "card 1".
  292.     err = CreateIndexObjectSpecifier('cair', &kAENullDescriptor, 1, &cardDesc);
  293.     require(err == noErr, FatalError);
  294.     
  295.     // Create descriptor for "power of card 1".
  296.     err = CreatePropertyObjectSpecifier(cProperty, &cardDesc, '42po', &powerDesc);
  297.     require(err == noErr, FatalError);
  298.     
  299.     err = setEvent.PutParameterDesc(keyDirectObject, powerDesc);
  300.     require(err == noErr, PutParameterDescFailed);
  301.     
  302.     err = setEvent.PutParameterDesc(keyAEData, powerOnDesc);
  303.     require(err == noErr, PutParameterDescFailed);
  304.     
  305.     err = setEvent.Send(kAEWaitReply);
  306.     require(err == noErr, SendFailed);
  307.     
  308. FatalError:
  309. AssignFailed:
  310. PutParameterDescFailed:
  311. SendFailed:
  312.     return err;
  313. }
  314.  
  315.  
  316. /*------------------------------------------------------------------
  317.     JoinNetwork
  318. ------------------------------------------------------------------*/
  319.  
  320. OSErr
  321. JoinNetwork(
  322.     ConstStr255Param    inNetwork)
  323. {
  324.     OSErr    err = noErr;
  325.     
  326.     AEAppleEvent    joinEvent('aeAP', 'aeJN', '1wse');
  327.     AEDescriptor    nameDesc(typeText, &inNetwork[1], inNetwork[0]);
  328.     
  329.     err = joinEvent.PutParameterDesc(keyDirectObject, nameDesc);
  330.     require(err == noErr, AEPutParamDescFailed);
  331.     
  332.     err = joinEvent.Send(kAEWaitReply);
  333.     require(err == noErr, AESendFailed);
  334.     
  335. AEPutParamDescFailed:
  336. AESendFailed:
  337.     return err;
  338. }
  339.  
  340.  
  341. /*------------------------------------------------------------------
  342.     LaunchAP
  343. ------------------------------------------------------------------*/
  344.  
  345. OSErr
  346. LaunchAP()
  347. {
  348.     OSErr    err = noErr;
  349.     FSSpec    appl = {0};
  350.     
  351.     err = FindFolderItemByTypeAndCreator(kOnSystemDisk, kAppleMenuFolderType, false, 'APPL', '1wna', &appl);
  352.     require(err == noErr, FindFolderFailed);
  353.     
  354.     err = LaunchIt(&appl, launchContinue | launchNoFileFlags);
  355.     require(err == noErr, LaunchItFailed);
  356.     
  357. FindFolderFailed:
  358. LaunchItFailed:
  359.     return err;
  360. }
  361.  
  362.  
  363. /*------------------------------------------------------------------
  364.     LaunchAPScripting
  365. ------------------------------------------------------------------*/
  366.  
  367. OSErr
  368. LaunchAPScripting()
  369. {
  370.     OSErr    err = noErr;
  371.     FSSpec    appl = {0};
  372.     
  373.     err = FindFolderItemByTypeAndCreator(kOnSystemDisk, kScriptingAdditionsFolderType, false, 'APPL', '1wse', &appl);
  374.     require(err == noErr, FindFolderFailed);
  375.     
  376.     err = LaunchIt(&appl, launchContinue | launchNoFileFlags | launchDontSwitch);
  377.     require(err == noErr, LaunchItFailed);
  378.     
  379. FindFolderFailed:
  380. LaunchItFailed:
  381.     return err;
  382. }
  383.  
  384.  
  385. /*------------------------------------------------------------------
  386.     QuitAPScripting
  387. ------------------------------------------------------------------*/
  388.  
  389. OSErr
  390. QuitAPScripting()
  391. {
  392.     ProcessSerialNumber    psn = {0};
  393.     
  394.     // Make sure the process is running because this might
  395.     // get called during startup.
  396.     if (FindProcessByCreator(&psn, '1wse'))
  397.     {
  398. // fix me - should wait several seconds
  399. #if 0
  400.         Boolean    wasOpen;
  401.         
  402.         SendQuitApplication(&wasOpen, '1wse');
  403.         check(wasOpen);
  404. #endif
  405.     }
  406.     
  407.     return noErr;
  408. }
  409.  
  410. /*------------------------------------------------------------------
  411.     SendQuitApplication
  412. ------------------------------------------------------------------*/
  413.  
  414. static OSErr
  415. SendQuitApplication (Boolean* wasOpen, OSType creator) {
  416.  
  417.     OSErr                    err                    = noErr;
  418.     ProcessSerialNumber        applicationPSN;
  419.     AEAddressDesc            applicationAddr;
  420.     AppleEvent                quitEvent;
  421.     AppleEvent                theReply;
  422.     
  423.     EmptyAEDesc (applicationAddr);
  424.     EmptyAEDesc (quitEvent);
  425.     EmptyAEDesc (theReply);
  426.  
  427.     // Find a process matching the creator, if any; if it is found, send it an
  428.     // AppleEvent to quit (it does support the core suite, right?)...
  429.     
  430.     *wasOpen = FindProcessByCreator (&applicationPSN, creator);
  431.     
  432.     if (*wasOpen) {
  433.         if (err == noErr) {
  434.             err = AECreateDesc (typeProcessSerialNumber, &applicationPSN, 
  435.                         sizeof (applicationPSN), &applicationAddr);
  436.         } // if
  437.         if (err == noErr) {
  438.             err = AECreateAppleEvent (kCoreEventClass, kAEQuitApplication,
  439.                         &applicationAddr, kAutoGenerateReturnID, kAnyTransactionID, 
  440.                         &quitEvent); 
  441.         } // if
  442.         if (err == noErr) {
  443.             err = AESend (&quitEvent, &theReply, kAENoReply | kAENeverInteract,
  444.                         kAEHighPriority, kAEDefaultTimeout, kNoIdleProc,
  445.                         kNoFilterProc);
  446.         } // if
  447.         if (err == noErr) {
  448.             if (!ProcessBecameInvalid (&applicationPSN, kTimeToQuit)) {
  449.                 err = kSampleCouldNotQuitIdx;    // We'll tell the user we tried...
  450.             } // if
  451.         } // if
  452.     } // if
  453.  
  454.     (void) AEDisposeDesc (&applicationAddr);
  455.     (void) AEDisposeDesc (&quitEvent);
  456.  
  457.     return err;
  458.  
  459. } // SendQuitApplication
  460.  
  461. // ------------------------------------------------------------------------------------------------- 
  462.  
  463. static OSErr
  464. LaunchIt (ConstFSSpecPtr theApplication, LaunchFlags theFlags) {
  465.  
  466.     OSErr                    err                    = noErr;
  467.     LaunchParamBlockRec        lpb = {0};
  468.  
  469.     lpb.launchBlockID         = extendedBlock;
  470.     lpb.launchEPBLength     = extendedBlockLen;
  471.     lpb.launchFileFlags     = kExtractFileFlagsFromFinder;
  472.     lpb.launchControlFlags     = theFlags;
  473.     lpb.launchAppSpec         = (FSSpecPtr) theApplication;
  474.     
  475.     err = LaunchApplication (&lpb);
  476.     
  477.     return err;
  478.  
  479. } // LaunchIt
  480.  
  481. // ------------------------------------------------------------------------------------------------- 
  482.  
  483. static Boolean
  484. FindProcessByCreator (ProcessSerialNumber* psn, OSType creator) {
  485.  
  486.     OSErr                    err                 = noErr;
  487.     Boolean                    found                = false;
  488.     ProcessInfoRec            curProcessInfo;
  489.     ProcessSerialNumber        curPSN; 
  490.     
  491.     SetFirstProcess (curPSN);
  492.     
  493.     // If we're running at INIT time, none of this will work (and we don't need to
  494.     // do it anyway!), so 
  495.     
  496.     if (ProcessManagerAvailable ()) {
  497.  
  498.         do {
  499.             curProcessInfo.processInfoLength     = sizeof (curProcessInfo);
  500.             curProcessInfo.processName            = NULL;
  501.             curProcessInfo.processAppSpec        = NULL;
  502.             if (err == noErr) {
  503.                 err = GetNextProcess (&curPSN);
  504.             } // if
  505.             if (err == noErr) {
  506.                 err = GetProcessInformation (&curPSN, &curProcessInfo);
  507.             } // if
  508.             if (err == noErr) {
  509.                 if (curProcessInfo.processSignature == creator) {
  510.                     *psn = curPSN;
  511.                     found = true;
  512.                     break;
  513.                 } // if
  514.             } // if
  515.         } while (err == noErr);
  516.     
  517.     } // if
  518.  
  519.     return found;
  520.  
  521. } // FindProcessByCreator
  522.  
  523. // ------------------------------------------------------------------------------------------------- 
  524.  
  525. static Boolean
  526. ProcessManagerAvailable (void) {
  527.  
  528.     OSErr        err;
  529.     SInt32        response;
  530.     Boolean        reply;
  531.     
  532.     err = Gestalt (gestaltOSAttr, &response);
  533.     
  534.     reply = (err == noErr) && (response & (1 << gestaltLaunchControl));
  535.     
  536.     return reply;
  537.  
  538. } // ProcessManagerAvailable
  539.  
  540. // ------------------------------------------------------------------------------------------------- 
  541.  
  542. static Boolean
  543. ProcessBecameInvalid (ProcessSerialNumber* psn, UInt32 timeoutInTicks) {
  544.  
  545.     OSErr            err                 = noErr;
  546.     Boolean            stillAround         = true;
  547.     UInt32            startTime             = LMGetTicks ();
  548.     UInt32            curTime                = startTime;
  549.     UInt32            endTime                = startTime + timeoutInTicks;
  550.     ProcessInfoRec    processInfo;
  551.     
  552.     // Wait around, being background friendly, for the specified process to 
  553.     // terminate...
  554.  
  555.     do {
  556.         ShareTime ();
  557.         if (err == noErr) {
  558.             processInfo.processInfoLength     = sizeof (processInfo);
  559.             processInfo.processName            = NULL;
  560.             processInfo.processAppSpec        = NULL;
  561.             err = GetProcessInformation (psn, &processInfo);
  562.             if ((err == paramErr) || (err == procNotFound)) {
  563.                 stillAround = false;
  564.                 break;
  565.             } // if
  566.         } // if
  567.         curTime = LMGetTicks ();
  568.     } while (curTime < endTime);
  569.     
  570.     return !stillAround;
  571.  
  572. } // ProcessBecameInvalid
  573.  
  574.