home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / UsageLogger 1.0 / UsageLogger.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-08  |  7.8 KB  |  337 lines  |  [TEXT/KAHL]

  1. //
  2. //    UsageLogger is a small faceless background application for system 7.
  3. //    When run it logs application usage.
  4. //
  5. //    Based on cSmallDaemon, 7/92 Greg Robbins, based on code by C.K. Haun
  6. //
  7. #include <Types.h>
  8. #include <QuickDraw.h>
  9. #include <ToolUtils.h>
  10. #include <AppleEvents.h>
  11. #include <GestaltEqu.h>
  12. #include <Processes.h>
  13. #include <Folders.h>
  14. #include <Files.h>
  15. #include <Packages.h>
  16. #include <Script.h>
  17.  
  18. #include "UsageLogger.h"
  19. //
  20. // Globals:
  21. //
  22. // 150 ticks is about 2.5 seconds
  23. //
  24. const long gSleepVal = 150;
  25.  
  26. const int gFlush_interval  = 100;
  27. //
  28. // Apple event handlers to be installed
  29. //
  30. pascal OSErr DoAEOpenApplication(
  31.     AppleEvent *theAppleEvent, AppleEvent *replyAppleEvent, long refCon)
  32. {
  33.     #pragma unused( theAppleEvent, replyAppleEvent, refCon)
  34.     return noErr;
  35. }
  36.  
  37. pascal OSErr UnhandledAEvent(
  38.     AppleEvent *theAppleEvent, AppleEvent *replyAppleEvent, long refCon)
  39. {
  40.     #pragma unused( theAppleEvent, replyAppleEvent, refCon)
  41.     return errAEEventNotHandled;
  42. }
  43.  
  44. pascal OSErr DoAEQuitApplication(
  45.     AppleEvent *theAppleEvent, AppleEvent *replyAppleEvent, long refCon)
  46. {
  47.     #pragma unused( theAppleEvent, replyAppleEvent)
  48.     *(Boolean *)refCon = true;
  49.     return noErr;
  50. }
  51.  
  52. pascal OSErr DoAELogText(
  53.     AppleEvent *theAppleEvent, AppleEvent *replyAppleEvent, long refCon)
  54. {
  55.     OSErr result;
  56.     unsigned long now;
  57.     long   theSize;
  58.     AEDesc theDesc;
  59.     
  60.     #pragma unused( replyAppleEvent)
  61.  
  62.     result = AEGetParamDesc( theAppleEvent, keyDirectObject, typeChar, &theDesc);
  63.     
  64.     if( result == noErr)
  65.     {
  66.         GetDateTime( &now);
  67.         basicTimeStamp( refCon, 'Log:', now);
  68.         
  69.         theSize = GetHandleSize( theDesc.dataHandle);
  70.     
  71.         if( theSize != 0)
  72.         {
  73.             writeATab( refCon);
  74.             HLock( theDesc.dataHandle);
  75.             FSWrite( refCon, &theSize, *theDesc.dataHandle);
  76.         }
  77.         AEDisposeDesc( &theDesc);    
  78.         writeAReturn( refCon);
  79.     }
  80.     return result;
  81. }
  82.  
  83. pascal OSErr DoAEFlushLog(
  84.     AppleEvent *theAppleEvent, AppleEvent *replyAppleEvent, long refCon)
  85. {
  86.     #pragma unused( theAppleEvent, replyAppleEvent)
  87.     return FlushVol( 0, refCon);
  88. }
  89.  
  90. OSErr InitAppleEventsStuff( Boolean *quitFlag, long foundVRefnum, short theFile)
  91. {
  92.     OSErr result;
  93.     
  94.     result = 
  95.             AEInstallEventHandler( kCoreEventClass, kAEOpenApplication,
  96.                 (AEEventHandlerUPP) DoAEOpenApplication, 0, false)
  97.                                     
  98.             || AEInstallEventHandler( kCoreEventClass, kAEOpenDocuments,
  99.                 (AEEventHandlerUPP) DoAEOpenDocuments, 0, false)
  100.                 
  101.             || AEInstallEventHandler( kCoreEventClass, kAEPrintDocuments,
  102.                 (AEEventHandlerUPP) DoAEPrintDocuments, 0, false)
  103.                 
  104.             || AEInstallEventHandler( kCoreEventClass, kAEQuitApplication,
  105.                 (AEEventHandlerUPP) DoAEQuitApplication, (long)quitFlag, false)
  106.  
  107.             || AEInstallEventHandler( 'Log:', 'flsh',
  108.                 (AEEventHandlerUPP) DoAEFlushLog, (long)foundVRefnum, false)
  109.  
  110.             || AEInstallEventHandler( 'Log:', 'log ',
  111.                 (AEEventHandlerUPP) DoAELogText, (long)theFile, false);
  112.     return result;
  113. }
  114.  
  115. void main( void)
  116. {
  117.     OSErr retCode;
  118.     long gestResponse;
  119.     
  120.     EventRecord mainEventRec;
  121.     Boolean eventFlag;
  122.  
  123.     ProcessSerialNumber lastProcessSeen;
  124.     
  125.     int to_go_till_flush = gFlush_interval;
  126.     long foundDirID;
  127.     short foundVRefnum;
  128.     short theFile;
  129.     Boolean quitFlag = false;
  130.  
  131.     Handle configResource = Get1Resource( 'pref', 128);
  132.     const config *theConfig = (config *)*configResource;    
  133.     //
  134.     // faceless background apps only get a 2K stack by default. If necessary,
  135.     // increase the stack size here (by calling GetApplLimit to find the current
  136.     // heap limit, and SetApplLimit to set it to a lower address, thus reserving
  137.     // more space for the stack)
  138.     //
  139.     InitGraf( &qd.thePort);
  140.     //
  141.     // is the Apple Event Manager available?
  142.     //
  143.     retCode = Gestalt( gestaltAppleEventsAttr, &gestResponse);
  144.     
  145.     if( (retCode != noErr) ||
  146.         (gestResponse & (1 << gestaltAppleEventsPresent)) == 0)
  147.     {
  148.         NotifyUserAndQuit( needsAppleEvents);
  149.     }
  150.     if( FindFolder( kOnSystemDisk, theConfig->prefsFolderType,
  151.                 kCreateFolder, &foundVRefnum, &foundDirID) == noErr)
  152.     {
  153.         FSSpec theFileSpec;
  154.         OSErr foutje = FSMakeFSSpec( foundVRefnum, foundDirID,
  155.                 (ConstStr255Param)*Get1Resource( 'STR ', logFileName), &theFileSpec);
  156.         if( (foutje == noErr) || (foutje == fnfErr))
  157.         {
  158.             (void)FSpCreate( &theFileSpec,
  159.                         theConfig->logFileCreator, 'TEXT', smSystemScript);
  160.             if( FSpOpenDF( &theFileSpec, fsWrPerm, &theFile) != noErr)
  161.             {
  162.                 NotifyUserAndQuit( outputFileOpenError);
  163.             }
  164.         } else {
  165.             NotifyUserAndQuit( couldNotSetDirectory);
  166.         }
  167.     } else {
  168.         NotifyUserAndQuit( couldNotSetDirectory);
  169.     }
  170.  
  171.     (void)SetFPos( theFile, fsFromLEOF, 0L);
  172.  
  173.     TimeStamp( theFile, 'strt');
  174.     //
  175.     // install Apple event handlers
  176.     //
  177.     if( InitAppleEventsStuff( &quitFlag, foundVRefnum, theFile) != noErr)
  178.     {
  179.         NotifyUserAndQuit( handlerInstallFailed);
  180.     }
  181.     //
  182.     // main event loop
  183.     //
  184.     if( GetCurrentProcess( &lastProcessSeen) != noErr)
  185.     {
  186.         quitFlag = true;
  187.     }
  188.     while( !quitFlag)
  189.     {
  190.         ProcessSerialNumber frontProcess;
  191.         Boolean result;
  192.  
  193.         eventFlag = WaitNextEvent( everyEvent, &mainEventRec, gSleepVal, nil);
  194.         
  195.         if( mainEventRec.what == kHighLevelEvent)
  196.         {
  197.             (void)AEProcessAppleEvent( &mainEventRec);
  198.         }
  199.         
  200.         if( (GetFrontProcess( &frontProcess) == noErr)
  201.                 && (SameProcess( &lastProcessSeen, &frontProcess, &result) == noErr)
  202.                 && !result)
  203.         {
  204.             ProcessInfoRec the_info;
  205.             unsigned char processNamebuf[ 32];
  206.             FSSpec processFSSpec;
  207.             
  208.             the_info.processInfoLength = sizeof( ProcessInfoRec);
  209.             the_info.processName = (StringPtr)processNamebuf;
  210.             the_info.processAppSpec = &processFSSpec;
  211.             
  212.             lastProcessSeen = frontProcess;
  213.             //
  214.             // different process:
  215.             //
  216.             if( GetProcessInformation( &frontProcess, &the_info) == noErr)
  217.             {
  218.                 long count = 4;
  219.                 TimeStamp( theFile, the_info.processSignature);
  220.                 
  221.                 to_go_till_flush -= 1;
  222.                 
  223.                 if( to_go_till_flush <= 0)
  224.                 {
  225.                     to_go_till_flush = gFlush_interval;
  226.                     (void)FlushVol( 0, foundVRefnum);
  227.                 }
  228.             }
  229.         }
  230.     }
  231.     TimeStamp( theFile, 'stop');
  232.     TimeStamp( theFile, '????');    // flushes the 'cache' maintained by TimeStamp
  233.     (void)FSClose( theFile);
  234.     (void)FlushVol( 0, foundVRefnum);
  235.     ExitToShell();
  236. }
  237.  
  238. void basicTimeStamp( short theFile, OSType theType, long now)
  239. {
  240.     Str255 thestring;
  241.     long size;
  242.     
  243.     IUDateString( now, shortDate, thestring);    
  244.     writePString( theFile, thestring);
  245.  
  246.     writeATab( theFile);
  247.  
  248.     IUTimeString( now, true, thestring);    
  249.     writePString( theFile, thestring);
  250.  
  251.     writeATab( theFile);
  252.  
  253.     size = 4;
  254.     (void)FSWrite( theFile, &size, &theType);
  255. }
  256.  
  257. void TimeStamp( short theFile, OSType theType)
  258. {
  259.     static TimeStampInfo theInfo = 
  260.     {
  261.         0L,         // unsigned long starting_time;
  262.         '????',        // OSType   theType;
  263.         0,            // short    theFile;
  264.     };
  265.     //
  266.     // First log the previous entry, if there was one:
  267.     //
  268.     unsigned long now;
  269.     GetDateTime( &now);
  270.  
  271.     if( theInfo.theFile != 0)
  272.     {
  273.         Str255 thestring;
  274.         long   size;
  275.         long numseconds = now - theInfo.starting_time;
  276.  
  277.         basicTimeStamp( theInfo.theFile, theInfo.theType, theInfo.starting_time);
  278.  
  279.         writeATab( theInfo.theFile);
  280.         
  281.         NumToString( numseconds, thestring);
  282.         writePString( theInfo.theFile, thestring);
  283.         
  284.         writeAReturn( theInfo.theFile);
  285.     }
  286.     //
  287.     // Then update the record
  288.     //
  289.     theInfo.starting_time = now;
  290.     theInfo.theType       = theType;
  291.     theInfo.theFile       = theFile;
  292. }
  293.  
  294. void NotifyUserAndQuit( const short messageno)
  295. {
  296.     NMRec the_note;
  297.     
  298.     the_note.qType    = nmType;
  299.     the_note.nmMark   = 0;
  300.     the_note.nmIcon   = 0L;
  301.     the_note.nmSound  = 0L;
  302.     the_note.nmStr    = *GetString( messageno);    // resource must be locked!!
  303.     the_note.nmResp   = myResponse;
  304.     the_note.nmRefCon = false;
  305.  
  306.     if( NMInstall( &the_note) == noErr)
  307.     {
  308.         while( the_note.nmRefCon == false)
  309.         {
  310.             EventRecord junk;
  311.             (void)WaitNextEvent( 0, &junk, gSleepVal, nil);
  312.         }
  313.     } else {
  314.         SysBeep( 9);
  315.     }
  316.     ExitToShell();
  317. }
  318.  
  319. pascal void myResponse( NMRecPtr theNMRec)
  320. {
  321.     theNMRec->nmRefCon = true;
  322.     (void)NMRemove( theNMRec);
  323. }
  324.  
  325. OSErr writeChar( short theFile, char theletter)
  326. {
  327.     long one = 1;
  328.     return FSWrite( theFile, &one, &theletter);
  329. }
  330.  
  331. OSErr writePString( short theFile, StringPtr string)
  332. {
  333.     long length = string[ 0];
  334.     
  335.     return FSWrite( theFile, &length, &string[ 1]);
  336. }
  337.