From 002a4bf41d3cbfc3bdf6ec94d12b9bb6f161bdf1 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Wed, 27 Apr 2005 12:59:53 +0000 Subject: [PATCH] *** empty log message *** svn path=/trunk/boinc/; revision=5945 --- checkin_notes | 23 + clientgui/BOINCGUIApp.cpp | 18 +- clientgui/MainFrame.cpp | 5 + clientgui/mac/mac_saver_module.cpp | 184 ++++-- mac_build/English.lproj/InfoPlist.strings | 4 +- mac_build/boinc.pbproj/project.pbxproj | 195 +++++- mac_installer/BOINC.pmsp | Bin 0 -> 1198 bytes mac_installer/License.rtf | 26 + mac_installer/LoginItemAPI.c | 690 ++++++++++++++++++++++ mac_installer/LoginItemAPI.h | 222 +++++++ mac_installer/PostInstall.cpp | 111 ++++ mac_installer/ReadMe.rtf | 35 ++ mac_installer/postinstall | 11 + mac_installer/postupgrade | 11 + 14 files changed, 1486 insertions(+), 49 deletions(-) create mode 100644 mac_installer/BOINC.pmsp create mode 100644 mac_installer/License.rtf create mode 100755 mac_installer/LoginItemAPI.c create mode 100755 mac_installer/LoginItemAPI.h create mode 100755 mac_installer/PostInstall.cpp create mode 100644 mac_installer/ReadMe.rtf create mode 100644 mac_installer/postinstall create mode 100755 mac_installer/postupgrade diff --git a/checkin_notes b/checkin_notes index ffa932b80f..e01a6b31ff 100755 --- a/checkin_notes +++ b/checkin_notes @@ -27750,3 +27750,26 @@ David 26 April 2005 shmem.C,h win_build/ boinc_cli.vcproj + +Charlie 27 April 2005 +Mac: created installer. Changed working directory from +user-specific "~/Library/Application Support/BOINC Data" +to global "/Library/Application Support/BOINC Data". +Fixed CViewProjects::OnProjectWebsiteClicked for Mac. +Added progress display to screensaver when no application +graphics. + + mac-installer/ + LoginItemAPI.c (new) + LoginItemAPI.h (new) + PostInstall.cpp (new) + postinstall (new) + postupgrade (new) + ReadMe.rtf (new) + License.rtf (new) + BOINC.pmsp (new) + clientgui/ + BOINCGUIApp.cpp + MainFrame.cpp + mac/ + mac_saver_module.cpp diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index ef0107dae6..ef64c14370 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -63,17 +63,16 @@ bool CBOINCGUIApp::OnInit() { wxString strDirectory = wxEmptyString; bool success; -// We have postponed implementing the umask change due to security concerns. -// umask(0); // Set file creation mask to make all files world-writable - // Our umask will be inherited by all our child processes - // Set the current directory ahead of the application launch so the core // client can find its files -#if 1 // Code for data in user's private directory +#if 0 // Code for separate data in each user's private directory wxChar buf[1024]; wxExpandPath(buf, "~/Library/Application Support"); strDirectory = wxT(buf); -#else // Code for data in shared directory +#else // All users share the same data + // The mac installer sets the "setuid & setgid" bits for the + // BOINC Manager and core client so any user can run them and + // they can operate on shared data. strDirectory = wxT("/Library/Application Support"); #endif @@ -205,8 +204,13 @@ bool CBOINCGUIApp::OnInit() { err = GetProcessInformation(&psn, &pInfo); } // Don't open main window if we were started automatically at login - if (pInfo.processSignature == 'lgnw') // Login Window app + if (pInfo.processSignature == 'lgnw') { // Login Window app m_bFrameVisible = false; + + // If the system was just started, we usually get a "Connection + // failed" error if we try to connect too soon, so delay a bit. + sleep(10); + } #endif // Show the UI diff --git a/clientgui/MainFrame.cpp b/clientgui/MainFrame.cpp index 1dc8d6b38b..d733991393 100644 --- a/clientgui/MainFrame.cpp +++ b/clientgui/MainFrame.cpp @@ -1428,7 +1428,12 @@ void CMainFrame::ExecuteBrowserLink(const wxString &strLink) { if (ft) { wxString cmd; if (ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(strLink))) { +#ifdef __WXMAC__ + cmd.Replace(wxT("<"), wxEmptyString); + cmd.Prepend(wxT("open ")); +#else cmd.Replace(wxT("file://"), wxEmptyString); +#endif ::wxExecute(cmd); } diff --git a/clientgui/mac/mac_saver_module.cpp b/clientgui/mac/mac_saver_module.cpp index a366119256..2ce69b9fcb 100755 --- a/clientgui/mac/mac_saver_module.cpp +++ b/clientgui/mac/mac_saver_module.cpp @@ -47,6 +47,7 @@ int drawGraphics(GrafPtr aPort); void drawPreview(GrafPtr aPort); void closeBOINCSaver(void); void setBannerText(ConstStringPtr msg, GrafPtr aPort); +void updateBannerText(ConstStringPtr msg, GrafPtr aPort); void drawBanner(GrafPtr aPort); void FlashIcon(void); OSErr FindBOINCApplication(FSSpecPtr applicationFSSpecPtr); @@ -58,6 +59,8 @@ OSStatus RPCThread(void* param); } // extern "C" #endif +// Flags for testing & debugging +#define SIMULATE_NO_GRAPHICS 0 #define CREATE_LOG 1 #ifdef __cplusplus @@ -72,6 +75,8 @@ void strip_cr(char *buf); #define BANNER_GAP 30 /* Space between repeats of banner text */ #define BANNERDELTA 2 /* Number of pixels to move banner each frame */ +#define BANNERFREQUENCY 90 /* Number of times per second to scroll banner */ +#define STATUSUPDATEINTERVAL 15 /* seconds between status display updates */ enum SaverState { SaverState_Idle, @@ -80,6 +85,7 @@ enum SaverState { SaverState_CoreClientSetToSaverMode, SaverState_CantLaunchCoreClient, + SaverState_ControlPanelTestMode, SaverState_UnrecoverableError }; @@ -88,9 +94,9 @@ extern int gGoToBlank; // True if we are to blank the screen extern int gBlankingTime; // Delay in minutes before blanking the screen -static Boolean wasAlreadyRunning; +static Boolean wasAlreadyRunning = false; static pid_t CoreClientPID = nil; -static Str255 bannerText; +static unsigned char msgBuf[2048], bannerText[2048]; static int bannerWidth; static SaverState saverState = SaverState_Idle; static StringPtr CurrentBannerMessage = 0; @@ -101,6 +107,10 @@ MPTaskID gRPC_thread_id; // IDs of the thread we create int gClientSaverStatus = 0; // status returned by get_screensaver_mode RPC Boolean gQuitRPCThread = false; // Flag to tell RPC thread to exit gracefully +// Display first status update after 5 seconds +static int statusUpdateCounter = ((STATUSUPDATEINTERVAL-5) * BANNERFREQUENCY); +Boolean gStatusMessageUpdated = false; + const ConstStringPtr CantLaunchCCMsg = "\pUnable to launch BOINC application."; const ConstStringPtr LaunchingCCMsg = "\pLaunching BOINC application."; const ConstStringPtr ConnectingCCMsg = "\pConnecting to BOINC application."; @@ -109,12 +119,14 @@ const ConstStringPtr BOINCNoAppsExecutingMsg = "\pBOINC is currently idle."; const ConstStringPtr BOINCNoProjectsDetectedMsg = "\pBOINC is not attached to any projects. Please attach to projects using the BOINC Manager."; const ConstStringPtr BOINCNoGraphicAppsExecutingMsg = "\pBOINC is currently not executing any applications with graphics"; const ConstStringPtr BOINCUnrecoverableErrorMsg = "\pSorry, an unrecoverable error occurred"; - +const ConstStringPtr BOINCTestmodeMg = "\pThis BOINC screensaver does not support Test mode"; // Returns desired Animation Frequency (per second) or 0 for no change int initBOINCSaver(Boolean ispreview) { int newFrequency = 15; + ProcessSerialNumber psn; + ProcessInfoRec pInfo; OSStatus err; if (ispreview) @@ -122,6 +134,23 @@ int initBOINCSaver(Boolean ispreview) { setBannerText(0, NULL); + // Ugly workaround for a problem with the System Preferences app + // For an unknown reason, when this screensaver is run using the + // Test button in the System Prefs Screensaver control panel, the + // control panel calls our stopAnimation function as soon as the + // science application opens a GLUT window. This problem does not + // occur when the screensaver is run nornally (from the screensaver + // engine.) So we just display a message and don't access the core + // client. + GetCurrentProcess(&psn); + memset(&pInfo, 0, sizeof(pInfo)); + pInfo.processInfoLength = sizeof( ProcessInfoRec ); + pInfo.processName = NULL; + err = GetProcessInformation(&psn, &pInfo); + if ( (err == noErr) && (pInfo.processSignature == 'sprf') ) { + saverState = SaverState_ControlPanelTestMode; + } + // If there are multiple displays, initBOINCSaver may get called // multiple times (once for each display), so we need to guard // against launching multiple instances of the core client @@ -166,8 +195,12 @@ OSStatus initBOINCApp() { return -1; else if (myPid == 0) // child { +#if 0 // Code for separate data in each user's private directory strcpy(buf, getenv("HOME")); strcat(buf, "/Library/Application Support/BOINC Data"); +#else // All users share the same data + strcpy(buf, "/Library/Application Support/BOINC Data"); +#endif status = chdir(buf); if (status) { perror("chdir"); @@ -195,11 +228,13 @@ int drawGraphics(GrafPtr aPort) { OSStatus err; ObscureCursor(); + + statusUpdateCounter++; switch (saverState) { case SaverState_LaunchingCoreClient: if (wasAlreadyRunning) - setBannerText(ConnectingCCMsg, aPort); + setBannerText(ConnectingCCMsg, aPort); else setBannerText(LaunchingCCMsg, aPort); @@ -265,7 +300,15 @@ int drawGraphics(GrafPtr aPort) { setBannerText(BOINCNoProjectsDetectedMsg, aPort); break; case SS_STATUS_NOGRAPHICSAPPSEXECUTING: - setBannerText(BOINCNoGraphicAppsExecutingMsg, aPort); + if (msgBuf[0] == 0) { + PLstrcpy(msgBuf, BOINCNoGraphicAppsExecutingMsg); + setBannerText(msgBuf, aPort); + } + if (gStatusMessageUpdated) { + updateBannerText(msgBuf, aPort); + gStatusMessageUpdated = false; + } + // Handled in RPCThread() break; case SS_STATUS_QUIT: // Handled in RPCThread() @@ -273,6 +316,10 @@ int drawGraphics(GrafPtr aPort) { } // end switch (gClientSaverStatus) break; + case SaverState_ControlPanelTestMode: + setBannerText(BOINCTestmodeMg, aPort); + break; + case SaverState_UnrecoverableError: setBannerText(BOINCUnrecoverableErrorMsg, aPort); break; @@ -290,7 +337,7 @@ int drawGraphics(GrafPtr aPort) { SetPort(aPort); drawBanner(aPort); SetGWorld(savePort, saveGDH); - newFrequency = 100; + newFrequency = BANNERFREQUENCY; } else newFrequency = 4; @@ -324,7 +371,7 @@ void closeBOINCSaver() { rpc = NULL; setBannerText(0, NULL); - + // Kill core client if we launched it if (!wasAlreadyRunning) if (CoreClientPID) @@ -339,10 +386,19 @@ void closeBOINCSaver() { OSStatus RPCThread(void* param) { - int val = 0; -// CC_STATE state; - AbsoluteTime timeToUnblock; - long time_to_blank; + int val = 0; + CC_STATE state; + AbsoluteTime timeToUnblock; + long time_to_blank; + char statusBuf[256]; + unsigned int len; + RESULTS results; + PROJECT* pProject; + bool bIsActive = false; + bool bIsExecuting = false; + bool bIsDownloaded = false; + int iResultCount = 0; + int iIndex = 0; while (true) { if (gQuitRPCThread) // If main thread has requested we exit @@ -357,7 +413,10 @@ OSStatus RPCThread(void* param) { time_to_blank = time(0) + (gBlankingTime * 60); else time_to_blank = 0; + +#if ! SIMULATE_NO_GRAPHICS val = rpc->set_screensaver_mode(true, time_to_blank, di); +#endif if (val == noErr) break; @@ -371,18 +430,11 @@ OSStatus RPCThread(void* param) { while (true) { if (gQuitRPCThread) // If main thread has requested we exit -{ MPExit(noErr); // Exit the thread -} timeToUnblock = AddDurationToAbsolute(durationSecond/4, UpTime()); MPDelayUntil(&timeToUnblock); -#if 0 - val = rpc->get_state(state); - if (val) { - } -#endif val = rpc->get_screensaver_mode(gClientSaverStatus); if (val) { // Attempt to reinitialize the RPC client and state @@ -390,32 +442,83 @@ OSStatus RPCThread(void* param) { rpc->init(NULL); // Error message after timeout? } + +#if SIMULATE_NO_GRAPHICS /* FOR TESTING */ + gClientSaverStatus = SS_STATUS_NOGRAPHICSAPPSEXECUTING; +#endif + if (gClientSaverStatus == SS_STATUS_NOGRAPHICSAPPSEXECUTING) { + if (statusUpdateCounter >= (STATUSUPDATEINTERVAL * BANNERFREQUENCY) ) { + statusUpdateCounter = 0; + + if (! gStatusMessageUpdated) { + PLstrcpy(msgBuf, BOINCNoGraphicAppsExecutingMsg); + + MPYield(); + val = rpc->get_state(state); + MPYield(); + if (val == 0) + val = rpc->get_results(results); + if (val == 0) { + iResultCount = results.results.size(); + + for (iIndex = 0; iIndex < iResultCount; iIndex++) { + bIsDownloaded = (RESULT_FILES_DOWNLOADED == results.results.at(iIndex)->state); + bIsActive = (results.results.at(iIndex)->active_task); + bIsExecuting = (CPU_SCHED_SCHEDULED == results.results.at(iIndex)->scheduler_state); + + if (!(bIsActive) || !(bIsDownloaded) || !(bIsExecuting)) continue; + + pProject = state.lookup_project(results.results.at(iIndex)->project_url); + if (pProject != NULL) { + len = sprintf(statusBuf, (" %s: %.2f%%"), + pProject->project_name.c_str(), + results.results.at(iIndex)->fraction_done * 100 + ); + + // Append C string to Pascal string + if ((len + msgBuf[0] + 1) < sizeof(msgBuf)) { + BlockMove(statusBuf, msgBuf+msgBuf[0]+1, len); + msgBuf[0] += len; + } + } // end if (pProject != NULL) + } // end for() loop + gStatusMessageUpdated = true; + } else { // rpc call returned error + rpc->close(); + rpc->init(NULL); + } // end if (rpc.get_results(results) {} else {} + + } // end if (! gStatusMessageUpdated) + + } // end if (statusUpdateCounter > time to update) + } // end if SS_STATUS_NOGRAPHICSAPPSEXECUTING if (gClientSaverStatus == SS_STATUS_QUIT) { rpc->set_screensaver_mode(false, 0, di); - MPExit(noErr); // Exit the thread + MPExit(noErr); // Exit the thread } - } + } // end while(true) } - void setBannerText(ConstStringPtr msg, GrafPtr aPort) { + if (msg == 0) + bannerText[0] = 0; + + if ((ConstStringPtr)CurrentBannerMessage != msg) + updateBannerText(msg, aPort); +} + + +void updateBannerText(ConstStringPtr msg, GrafPtr aPort) { CGrafPtr savePort; RGBColor saveBackColor; Rect wRect; - if ((ConstStringPtr)CurrentBannerMessage == msg) - return; - CurrentBannerMessage = (StringPtr)msg; - - if (msg == 0) { - bannerText[0] = 0; - if (aPort != NULL) - drawBanner(aPort); + + if (aPort == NULL) return; - } GetPort(&savePort); SetPort(aPort); @@ -427,12 +530,15 @@ void setBannerText(ConstStringPtr msg, GrafPtr aPort) { EraseRect(&wRect); RGBBackColor(&saveBackColor); - BlockMove(msg, bannerText, msg[0]+1); - TextSize(24); - TextFace(bold); - bannerWidth = StringWidth(bannerText) + BANNER_GAP; - // Round up bannerWidth to an integral multiple of BANNERDELTA - bannerWidth = ((bannerWidth + BANNERDELTA - 1) / BANNERDELTA) * BANNERDELTA; + if (msg) { + BlockMove(msg, bannerText, msg[0]+1); + TextSize(24); + TextFace(bold); + bannerWidth = StringWidth(bannerText) + BANNER_GAP; + // Round up bannerWidth to an integral multiple of BANNERDELTA + bannerWidth = ((bannerWidth + BANNERDELTA - 1) / BANNERDELTA) * BANNERDELTA; + } + SetPort(savePort); } @@ -444,9 +550,11 @@ void drawBanner(GrafPtr aPort) { short x, y; Rect wRect; FontInfo fInfo; - static short bannerPos; + if (aPort == NULL) + return; + GetGWorld(&savePort, &saveGDH); SetPort(aPort); @@ -485,7 +593,7 @@ pid_t FindProcessPID(char* name, pid_t thePID) { FILE *f; char buf[1024]; - size_t n; + size_t n = 0; pid_t aPID; if (name != NULL) // Search ny name diff --git a/mac_build/English.lproj/InfoPlist.strings b/mac_build/English.lproj/InfoPlist.strings index 8934fbc0b4..d3557d815a 100755 --- a/mac_build/English.lproj/InfoPlist.strings +++ b/mac_build/English.lproj/InfoPlist.strings @@ -1,5 +1,5 @@ /* Localized versions of Info.plist keys */ CFBundleName = "BOINC"; -CFBundleShortVersionString = "BOINC version 4.30"; -CFBundleGetInfoString = "BOINC version 4.30, Copyright 2005 University of California."; +CFBundleShortVersionString = "BOINC version 4.68"; +CFBundleGetInfoString = "BOINC version 4.68, Copyright 2005 University of California."; diff --git a/mac_build/boinc.pbproj/project.pbxproj b/mac_build/boinc.pbproj/project.pbxproj index 060fd6a4f3..6052f599ad 100755 --- a/mac_build/boinc.pbproj/project.pbxproj +++ b/mac_build/boinc.pbproj/project.pbxproj @@ -42,7 +42,6 @@ DEAD_CODE_STRIPPING = YES; DEPLOYMENT_POSTPROCESSING = YES; GCC_ENABLE_FIX_AND_CONTINUE = NO; - OTHER_CPLUSPLUSFLAGS = "-D__WXDEBUG__"; ZERO_LINK = NO; }; isa = PBXBuildStyle; @@ -68,6 +67,7 @@ DD40CDF907F0386A0096C645, DDAEC9E107FA583B00A7BC36, DD96AFF90811075000A06F22, + DD1277B3081F3D67007B5DE1, ); isa = PBXGroup; name = Products; @@ -106,6 +106,7 @@ DD40CDF807F0386A0096C645, DDAEC9E007FA583B00A7BC36, DD96AFF80811075000A06F22, + DD1277B2081F3D67007B5DE1, ); }; 20286C29FDCF999611CA2CEA = { @@ -113,6 +114,7 @@ DD40827D07D30AA800163EF5, F54B8FBE02AC0A0C01FB7237, DD81C3F707C5D03B0098A04D, + DD1277BC081F3E59007B5DE1, DDF9385307E288F0004DC076, F515955F029EB02001F5651B, F54FF8B6029F2FFC012012A7, @@ -122,6 +124,7 @@ 195DF8C9FE9D4F0611CA2CBB, DD40CDFA07F0386B0096C645, DD96AFFA0811075100A06F22, + DD1277B5081F3D67007B5DE1, ); isa = PBXGroup; name = "¬´PROJECTNAME»"; @@ -691,6 +694,191 @@ settings = { }; }; + DD1277AF081F3D67007B5DE1 = { + buildActionMask = 2147483647; + files = ( + DD1277E5081F4461007B5DE1, + ); + isa = PBXResourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + DD1277B0081F3D67007B5DE1 = { + buildActionMask = 2147483647; + files = ( + DD1277C2081F3E73007B5DE1, + DD1277C4081F3E73007B5DE1, + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + DD1277B1081F3D67007B5DE1 = { + buildActionMask = 2147483647; + files = ( + DD1277E6081F44C1007B5DE1, + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + DD1277B2081F3D67007B5DE1 = { + buildPhases = ( + DD1277AF081F3D67007B5DE1, + DD1277B0081F3D67007B5DE1, + DD1277B1081F3D67007B5DE1, + ); + buildRules = ( + ); + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = "PostInstall-Info.plist"; + INSTALL_PATH = "$(USER_APPS_DIR)"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = "-framework Carbon"; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = Postinstall; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + }; + dependencies = ( + ); + isa = PBXNativeTarget; + name = Installer; + productName = Installer; + productReference = DD1277B3081F3D67007B5DE1; + productSettingsXML = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Installer + CFBundleIdentifier + com.yourcompany.Installer + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + +"; + productType = "com.apple.product-type.application"; + }; + DD1277B3081F3D67007B5DE1 = { + explicitFileType = wrapper.application; + includeInIndex = 0; + isa = PBXFileReference; + path = Postinstall.app; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + DD1277B5081F3D67007B5DE1 = { + isa = PBXFileReference; + lastKnownFileType = text.xml; + name = "Installer-Info.plist"; + path = "/Volumes/Moon/BOINC_Mac/boinc/mac_build/Installer-Info.plist"; + refType = 0; + sourceTree = ""; + }; + DD1277BC081F3E59007B5DE1 = { + children = ( + DD1277BE081F3E73007B5DE1, + DD1277BF081F3E73007B5DE1, + DD1277C0081F3E73007B5DE1, + DD12787F081F464E007B5DE1, + DD127880081F464E007B5DE1, + ); + isa = PBXGroup; + name = mac_installer; + path = ""; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + DD1277BE081F3E73007B5DE1 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = LoginItemAPI.c; + path = ../mac_installer/LoginItemAPI.c; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + DD1277BF081F3E73007B5DE1 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = LoginItemAPI.h; + path = ../mac_installer/LoginItemAPI.h; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + DD1277C0081F3E73007B5DE1 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = PostInstall.cpp; + path = ../mac_installer/PostInstall.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + DD1277C2081F3E73007B5DE1 = { + fileRef = DD1277BE081F3E73007B5DE1; + isa = PBXBuildFile; + settings = { + }; + }; + DD1277C4081F3E73007B5DE1 = { + fileRef = DD1277C0081F3E73007B5DE1; + isa = PBXBuildFile; + settings = { + }; + }; + DD1277E5081F4461007B5DE1 = { + fileRef = DD1277B5081F3D67007B5DE1; + isa = PBXBuildFile; + settings = { + }; + }; + DD1277E6081F44C1007B5DE1 = { + fileRef = 20286C33FDCF999611CA2CEA; + isa = PBXBuildFile; + settings = { + }; + }; + DD127876081F44E5007B5DE1 = { + containerPortal = 20286C28FDCF999611CA2CEA; + isa = PBXContainerItemProxy; + proxyType = 1; + remoteGlobalIDString = DD1277B2081F3D67007B5DE1; + remoteInfo = Installer; + }; + DD127877081F44E5007B5DE1 = { + isa = PBXTargetDependency; + target = DD1277B2081F3D67007B5DE1; + targetProxy = DD127876081F44E5007B5DE1; + }; + DD12787F081F464E007B5DE1 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + name = postinstall.txt; + path = ../mac_installer/postinstall.txt; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + DD127880081F464E007B5DE1 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.csh; + name = postupgrade; + path = ../mac_installer/postupgrade; + refType = 2; + sourceTree = SOURCE_ROOT; + }; DD2D25CB07FAB41700151141 = { fileEncoding = 30; isa = PBXFileReference; @@ -1258,11 +1446,13 @@ buildRules = ( ); buildSettings = { - GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; INSTALL_PATH = /usr/local/lib; LIBRARY_STYLE = STATIC; OTHER_CFLAGS = "-D_THREAD_SAFE -include ../config.h"; + OTHER_CPLUSPLUSFLAGS = "-D_THREAD_SAFE -include ../config.h"; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = boinc; @@ -3131,6 +3321,7 @@ DDBD681507FA830E0082C20D, DD791FF10819063C00BE2906, DDBD681707FA830E0082C20D, + DD127877081F44E5007B5DE1, ); isa = PBXAggregateTarget; name = Build_All; diff --git a/mac_installer/BOINC.pmsp b/mac_installer/BOINC.pmsp new file mode 100644 index 0000000000000000000000000000000000000000..fc07e09cf5e3bb3385506d16c5899a5bfe86c34b GIT binary patch literal 1198 zcmah}-D(q25YF0yQj3Mws`vx-PAW8ldMTJTtSls(khS%)oa|2GY0jP#&z^0Gcj9p$ zAfS>I+M*Y}Onna@!`ZXh9|e&FvYGkjo0)HBcKN!Rj3J1W1QLE&`lYRxTI*Ym-HsLM zGw>)MGUyV2M21k)dd0E#gsd2@xn8G#1iq?$n&L-WPHl<|8?LutXi{HM!HJw;_^Rtw z{(sgM-AK_$;wg!#EHpjF?A_7OW@OldND-+Th9Q~i`RQ5@-o;cxuy7gU%_3kw0{qH0 ziALx##BLn+L1ON!u6ICK3^mNLt!J~EiM?IK_JmLeg2f?pIGdpJ>`ZIRKer5Sby03!yixUN^LlnRQN1k$uN&lHoA~uyFIhfq;oXW@`Y7EOEA4*! O|H1e&I82W-Nqz%j+~Cmw literal 0 HcmV?d00001 diff --git a/mac_installer/License.rtf b/mac_installer/License.rtf new file mode 100644 index 0000000000..79a94837ec --- /dev/null +++ b/mac_installer/License.rtf @@ -0,0 +1,26 @@ +{\rtf1\mac\ansicpg10000\cocoartf102 +{\fonttbl\f0\fswiss\fcharset77 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\vieww12000\viewh14400\viewkind0 +\deftab720 +\pard\pardeftab720\ql\qnatural + +\f0\fs24 \cf0 Berkeley Open Infrastructure for Network Computing (BOINC)\ +\ +License Agreement\ +\ +Please carefully read the following terms and conditions before using this software. Your use of this software indicates your acceptance of this license agreement and warranty.\ +\ +Disclaimer of Warranty\ +\ +THIS SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT WARRANTIES AS TO PERFORMANCE OR MERCHANTABILITY OR ANY OTHER WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE IS OFFERED.\ +\ +Restrictions\ +\ +You may use this software on a computer system only if you own the system or have the permission of the owner.\ +\ +Distribution\ +\ +This is free software.It is distributed under the terms of the GNU Lesser General Public Licenseas published by the Free Software Foundation (http://www.fsf.org/).The source code may be obtainedfrom the BOINC web site (http://boinc.berkeley.edu).\ +\ +} \ No newline at end of file diff --git a/mac_installer/LoginItemAPI.c b/mac_installer/LoginItemAPI.c new file mode 100755 index 0000000000..68c2a57703 --- /dev/null +++ b/mac_installer/LoginItemAPI.c @@ -0,0 +1,690 @@ +/* + File: LoginItemAPI.c + + Copyright: © 2000-2003 by Apple Computer, Inc., all rights reserved. + + Bugs?: For bug reports, consult the following page on + the World Wide Web: + + http://developer.apple.com/bugreporter/ + +*/ +#import "LoginItemAPI.h" + +/***************************************************************************************************/ +// AddLoginItemWithPropertiesToUser +//**************************************************************************************************/ +// This function will add a LoginItem to the list of LoginItems when called. The properties +// given to the new LoginItem are passed when calling the function. Note that *no* check is made +// when adding the LoginItem to ensure that the path points to a valid application. Note that the LoginItem +// Is always added to the *end* of the list of LoginItems. +//**************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToChange) -> A constant which represents which users preferences +// we want to change. In this case there are two alternatives: kCurrentUser which +// changes the preferences of the current user. The second alternative is kAllUsers. +// The kAllUsers LoginItems are launched for all users on the system. You must be root +// or admin to use the kAllUsers option. +// Second Parameter (AbsolutePath) -> The absolute path of the application to be launched +// expressed as a Standard C string. (example: "/Applications/Clock") +// Third Parameter (HidetheApplicationOnStartup) -> A value representing if you want +// your application to be hidden at login time. kHideOnLaunch if you want the +// application to be hidden after it is launched. If you want the application to show +// up normally use be hidden use kDoNotHideOnLaunch +// +// Output Parameters: +// Return -> This function returns a boolean value representing if the function was successful. +// The function returns true if the LoginItem was successfully added. False if +// otherwise. No additional error codes are returned. +// Other Notes: This code doesn't work properly if more than one application is attempting to write to +// the LoginItems preference at once. +// Also no check is made to ensure that what you are adding to the LoginItem list isn't a +// duplicate. If there is a duplicate however only one instance of the application is launched +//**************************************************************************************************/ + +Boolean AddLoginItemWithPropertiesToUser(CFStringRef WhosPreferencesToChange, const char* AbsolutePath, Boolean HidetheApplicationOnLaunch) +{ + CFStringRef PreferenceName, MainKeyName; + CFArrayRef ArrayOfLoginItemsFixed; + Boolean Success; + CFMutableArrayRef ArrayOfLoginItemsModifiable; + CFDictionaryRef EmptyLoginItem; + CFMutableDictionaryRef NewLoginItem; + + //Generating the Lookup keys. Lookups are done via keys which are CFStrings. + CFStringRef HideKey = CFStringCreateWithCString(NULL,"Hide",kCFStringEncodingASCII); + CFBooleanRef HideValue; + + CFStringRef PathKey = CFStringCreateWithCString(NULL,"Path",kCFStringEncodingASCII); + CFStringRef PathValue; + + //Turning the "hide" boolean value passed as kHideOnLaunch, kDoNotHideOnLaunch into the proper type (CFBooleanRef). + if (HidetheApplicationOnLaunch == true) + { + HideValue = kCFBooleanTrue; + } + else + { + HideValue = kCFBooleanFalse; + } + + //doing sanity check on the name of the user passed in. Note we can use direct compairson because the pointer values and memory values should be identical to the constants. + if ((WhosPreferencesToChange != kCurrentUser) && (WhosPreferencesToChange != kAllUsers)) + { + return(false); + } + //Converting the Absolute path passed in to the format accepted by the CFPreferences API's (CFString format). + //For developers localizing to different languages: You should replace the kCFStringEncodingASCII with kCFStringEncodingUnicode and then what you pass in as the absolute path should be a unicode string. This will allow you to add LoginItems localized to different languages where the path can contain non-ascii characters. + PathValue = CFStringCreateWithCString(NULL,AbsolutePath,kCFStringEncodingASCII); + + //The name of the preference we are going to edit as a CFString. In this case it is loginwindow.plist + PreferenceName = CFSTR(kAppStr); //Note: CFString constants do not need to be released. + + //The name of the main or first key referenced in the preference file. In this case it is: AutoLaunchedApplicationDictionary + MainKeyName = CFSTR(kKeyStr); //Note: CFString constants do not need to be released. + + //Getting the array of LoginItems from the LoginItems preference file. + //Parameters: + //First Parameter: The key used to look up the array information. + //Second Parameter:Name of the preference Item (loginwindow.plist in this case), + //Third Parameter: Which user(s) will be effected. We either want the current user (kCurrentUser) or all users (kAllUsers) + //Fourth Parameter: We set this to anyhost because LoginItems always make use of Anyhost. + //Note: The return value will be null if the preference currently does not exist. + //Note that the structure returned must be released later. + + ArrayOfLoginItemsFixed = CFPreferencesCopyValue(MainKeyName, PreferenceName, WhosPreferencesToChange, kCFPreferencesAnyHost); + + //If the preference loginwindow.plist doesn't exist (ArrayOfLoginItemsFixed == null) then we will create the preference from scratch. The first step is to create an empty array. Afterwards we will insert our LoginItem into the previously empty array of LoginItems. + if( ArrayOfLoginItemsFixed == NULL) //handling case where no LoginItems exist yet. + { + //There must not be a loginwindow preference. We will create one by first creating an empty array of LoginItems. This will serve as our empty list of LoginItems which we will add to later. + //Note we must release the returned value. + ArrayOfLoginItemsFixed = CFArrayCreate(NULL, NULL, 0, NULL); + + //If creating the array failed then we give up. When giving up we always release required data types. + if (ArrayOfLoginItemsFixed == NULL) + { + return(false); + } + } + + //We want to get a modifiable version of the LoginItems. The modifiable version is where we will make all our changes before saving the LoginItems back to disk. + //First Parameter: using default CFAllocator. + //Second Paramater: want a non-bounded array so set this parameter to 0. This prevents the system from limiting the size of the array we want to use. + //Third Parameter: copy of the original list of LoginItems (the fixed list from before). + ArrayOfLoginItemsModifiable = CFArrayCreateMutableCopy(NULL,0,ArrayOfLoginItemsFixed); + + //If this operation failed then we release allocated structures and give up + if (ArrayOfLoginItemsModifiable == NULL) + { + CFRelease(ArrayOfLoginItemsFixed); + return(false); + } + + //Here we are creating an empty LoginItem. Actually a LoginItem itself is just a CFDictionary + //Note that the return value must be released later. + EmptyLoginItem = CFDictionaryCreate(NULL,NULL,NULL, 0,NULL, NULL); + + //If this operation failed then we release allocated structures and give up + if (EmptyLoginItem == NULL) + { + CFRelease(ArrayOfLoginItemsFixed); + CFRelease(ArrayOfLoginItemsModifiable); + return(false); + } + + //OK here we create an empty modifiable LoginItem from the emptyLoginItem which is fixed. + //First Parmater: NULL because we are using current allocator + //Second Paramater: want a non-bounded array so set this parameter to 0. This prevents the system from limiting the size of the array we want to use. + //Third parameter: The empty LoginItem which we are making a copy of. + //Note that we have to release the new LoginItem at the end. + NewLoginItem = CFDictionaryCreateMutableCopy(NULL,0, EmptyLoginItem); + + //If this operation failed then we release allocated structures and give up + if (NewLoginItem == NULL) + { + CFRelease(EmptyLoginItem); + CFRelease(ArrayOfLoginItemsModifiable); + CFRelease(ArrayOfLoginItemsFixed); + return(false); + } + + //This is where we add the new LoginItem to the currently empty list + //FirstParameter: the LoginItem list we are adding to. + //Second Parameter: The key/value we are going to set. + //Third Parameter: The value that the LoginItem will have. + + CFDictionaryAddValue(NewLoginItem,HideKey, HideValue); + CFDictionaryAddValue(NewLoginItem,PathKey, PathValue); + + //We are appending the new (finished) LoginItem to the list of LoginItems. + CFArrayAppendValue(ArrayOfLoginItemsModifiable, NewLoginItem); + + //Here we write the settings back to the preference stored in memory. + //Parameters: + //First Parameter: The key used to look up the array information. + //Second Parameter: The LoginItems list to write out to disk. + //Third Parameter:Name of the preference Item (loginwindow preference in this case), + //Fourth Parameter: Which user(s) will be effected. We either want the current user (kCurrentUser) or all users (kAllUsers) + //Fifth Parameter: We set this to anyhost since LoginItems always use anyhost. + CFPreferencesSetValue(MainKeyName,ArrayOfLoginItemsModifiable,PreferenceName, WhosPreferencesToChange, kCFPreferencesAnyHost); + + //Here we write the preference file in memory back to the hard disk. + Success = CFPreferencesSynchronize(PreferenceName, WhosPreferencesToChange, kCFPreferencesAnyHost); + + //If this operation failed then we release allocated structures and give up + if (Success == false) + { + CFRelease(NewLoginItem); + CFRelease(EmptyLoginItem); + CFRelease(ArrayOfLoginItemsModifiable); + CFRelease(ArrayOfLoginItemsFixed); + return(false); + } + + //Releasing all the data structures which need releasing. + CFRelease(NewLoginItem); + CFRelease(EmptyLoginItem); + CFRelease(ArrayOfLoginItemsModifiable); + CFRelease(ArrayOfLoginItemsFixed); + + return(true); //we return true because all operations succeeded which means the LoginItems were successfully updated. +} + +/**************************************************************************************************/ +// ReturnLoginItemPropertyAtIndex +//**************************************************************************************************/ +// This function will return the list of LoginItems as a CFArray. +//**************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to examine. The two alternatives are: kCurrentUser which lists the LoginItems +// which are specific to that user (these are preferences found in /Users//Library/Preferences) +// and kAnyUsers which lists LoginItems which are common to all users on the system (these +// preferences are found in /Library/Preferences/). +// Second Parameter (RequestType) -> A constant representing which type of request for information you are making. +// There are currently three request types. kFullPathInfo which causes this routine to return the +// absolute path to the LoginItem which is stored as a C String (example return value: +// "/Applications/Clock.app"). Second alternative is kApplicationNameInfo which causes the routine to +// return the name of the application as a C string (example return value: "Clock.app"). Third +// alternative is kHideInfo which causes the routine to return the hide current status as a C string. +// The two return types possible are the C Strings "Hide" and "DoNotHide" (example return value: "Hide") +// Third Parameter (LoginItemIndex) -> An integer representing the LoginItem index. Note that the LoginItems are +// stored as an array indexed from 0 to N-1 where N is the number of LoginItems. Note that if an invalid +// index is passed then you will get a return value of NULL indicating error status. +// +// Output Parameters: +// Return -> This function returns a value of NULL if an error has occurred (likely caused by attempting to index an +// invalid LoginItemIndex). If no error has occurred then a C String is returned which represents the data +// requested on the LoginItem at the index given. The three return types are: +// 1) For a kFullPathInfo request the absolute path of the LoginItem is returned (example: +// "/Applications/TextEdit"). 2) For a kApplicationNameInfo request only the LoginItem name is returned +// with no path (example: "TextEdit"). 3) For a kHideInfo request either the C string "Hide" is returned +// if LoginItem is hidden on launch or the C string value is "DoNotHide" if the LoginItem isn't hidden on +// launch +// Other Notes: The actual indexing of the LoginItem array starts at zero and goes up to N-1 where N is the number of +// LoginItems. Also, the order that the LoginItems are listed in the array is consistent with the ordering +// of the LoginItems within the preference file. Note that the ordering of the LoginItems in the array +// *does not* correspond to the order which the LoginItems are launched. The order which LoginItems are +// launched are determined by OSX at Login time and is based on what launch order would be most efficent. +//**************************************************************************************************/ + +char ReturnCharacterArray [kLoginItemInfoLength]; //allocating a character array where the return result will be stored. + +char* ReturnLoginItemPropertyAtIndex(CFStringRef WhosPreferencesToList, int RequestType, int LoginItemIndex) +{ + CFArrayRef ArrayOfLoginItemsFixed; + CFDictionaryRef LoginItemWeAreExaming; + CFStringRef PreferenceName, MainKeyName; + CFStringRef LoginPathInfoAsCFString; + CFStringRef PathKey, HideKey; + CFBooleanRef HideValue; + + char* StringToReturn; + char* TempString; + + //Doing a sanity check on the request type passed in. If request type doesn't match something we know we return NULL representing an error + if ((RequestType != kApplicationNameInfo) && (RequestType != kHideInfo) && (RequestType != kFullPathInfo)) + { + return(NULL); + } + + //Doing a sanity check on the LoginItem index. Return error if not valid index. + if (LoginItemIndex < 0) + { + return(NULL); + } + + //doing sanity check on the name of the user passed in. Note we can use direct compairson because the pointer values and memory values should be identical to the constants. + if ((WhosPreferencesToList != kCurrentUser) && (WhosPreferencesToList != kAllUsers)) + { + return(NULL); + } + + //Generating the Lookup keys. Lookups are done via keys which are CFStrings. + HideKey = CFStringCreateWithCString(NULL,"Hide",kCFStringEncodingASCII); + //This is the key used when looking up using the kFullPathInfo or kApplicationNameInfo. + PathKey = CFStringCreateWithCString(NULL,"Path",kCFStringEncodingASCII); + + //We need the name of the Application to look up in order look up the LoginItem list. In this the name is loginwindow.plist + PreferenceName = CFSTR(kAppStr); //Note: CFString constants do not need to be released. + + //The name of the main or first key referenced in the preference file. In this case it is: AutoLaunchedApplicationDictionary + MainKeyName = CFSTR(kKeyStr); //Note: CFString constants do not need to be released. + + //Getting the array of LoginItems from the LoginItems preference file. + //Parameters: + //First Parameter: The key used to look up the array information. + //Second Parameter:Name of the preference Item (loginwindow.plist in this case), + //Third Parameter: Which user(s) will be effected. We either want the current user (kCurrentUser) or all users (kAllUsers) + //Fourth Parameter: We set this to anyhost because LoginItems always make use of Anyhost. + //Note: The return value will be null if the preference currently does not exist. + //Note that the structure returned must be released later. + + ArrayOfLoginItemsFixed = CFPreferencesCopyValue(MainKeyName, PreferenceName, WhosPreferencesToList, kCFPreferencesAnyHost); + + //If the preference loginwindow.plist doesn't exist (ArrayOfLoginItemsFixed == null) then we know the size of the array is zero. This means that all queries on the database will result in returning NULL because there is no elements to look up. Thus we return null at this point. Note that the user of this function should normally call LoginItemsCount first to know how many items there are before asking about info on indiviual items. + if( ArrayOfLoginItemsFixed == NULL) //handling case where no LoginItems exist and can't do any lookups. + { + return(NULL); //returning null since there are no items to return information on + } + + //since we got back a vaild array of LoginItems now we will query the specific index of the LoginItem array that we are interested in. + //We do the lookup using a CFArrayGetValueAtIndex call. + //First Parameter: The array to query. + //Second Parameter: The index we want in this case whatever the user of this function passed in. We have to convert to a CFIndex which in reality is just a signed integer. + LoginItemWeAreExaming = (CFDictionaryRef) CFArrayGetValueAtIndex(ArrayOfLoginItemsFixed, (CFIndex) LoginItemIndex); + + if (LoginItemWeAreExaming == NULL) //if dictionary returned is null (invalid) then we give up. + { + return(NULL); //returning null since the value returned is not valid. + } + + //the request was for the path info in the full path case or the application name case the code is pretty much the same except we pull out the path at the end for the application name. + if ((RequestType == kFullPathInfo) || (RequestType == kApplicationNameInfo)) { + //Here we need to determine if the key we are looking for is present. If it isn't then the LoginItem is either corrupted or in a format we don't understand. In either case if the key we are looking for isn't present then we give up. + //We determine validity using CFDictionaryContainsKey to see if the key we are looking for is there + //First parameter: The CFdictionary to search in this case the LoginItem we are looking at (LoginItems are actually stored as CFDictionaries + //Second Paramter: the key we are looking for. + if (CFDictionaryContainsKey(LoginItemWeAreExaming,PathKey) == false) + { + CFRelease(ArrayOfLoginItemsFixed); + return(NULL); //returning null since LoginItems are corrupted or in a non-reconized format + } + + //Here we get a copy of the path as a CFString. we use a combination of calls of CFStringCreateCopy and CFDictionaryGetValue. The CFString call just makes a copy of the return value (like strcpy does) which later needs to be released. The CFDictionaryGetValue call will return the CFString reprenting the path. + LoginPathInfoAsCFString = CFStringCreateCopy(NULL, CFDictionaryGetValue(LoginItemWeAreExaming,PathKey)); + + //now that we have the path as a CFString we will convert to a standard C string for returning later. We use CFStringGetCStringPtr to do this + //First Parameter: CFString to be converted to C String + //Second Parameter: A pointer to the buffer which is where the C string will be placed. + //Third Parameter: The length of the buffer that we are putting the C string into. If the CFString is too long for the buffer then the call returns an error (NULL) + //Fourth Paramter: Encoding Type. We use encoding type of ASCII for simplicity to developers. + //**Note to engineers localizing this API to a non-english format: The encoding used below kCFStringEncodingASCII is simplistic and should be replaced with kCFStringEncodingUnicode. The return result will be in unicode format of the path and will handle the case where you want to lookup paths that have non ascii characters in the path. The reason I don't use unicode by default is for simplicity of use to the majority of developers. + CFStringGetCString(LoginPathInfoAsCFString, (char*) (&ReturnCharacterArray), kLoginItemInfoLength, kCFStringEncodingASCII); + + //Now if the application name is request we will strip off the beginning of the path leaving only the application or alias name. Note that this assumes the string it is parsing is a ASCII string. How this works is with multiple calls to strtok. strtok returns a pointer to the string *after* the next "/" character in the string. This continues until strtok returns NULL which means that there are no more "/" in the string (we are at the end of the string). This means that what is left is the filename and this is what we want to return (example: "Clock.app" from "/Applications/Clock.app"). + if (RequestType == kApplicationNameInfo) + { + TempString = (char*)strtok(ReturnCharacterArray, "/"); + + while (TempString != NULL) + { + StringToReturn = TempString; + TempString = (char*) strtok(NULL, "/"); //successive calls to strtok with the first argument as NULL continues the search for "/" from where we left off. + }//endwhile + }//endif + else + { //if we only want to return the entire path then the string we want to return is the entire path which is just a pointer to the character array. + StringToReturn = (char*) ReturnCharacterArray; + }//end else + + CFRelease(LoginPathInfoAsCFString); //need to release this here since it was allocated. + }//end get path info section + + else //now at the begining of the code which is executed if the Hide info is requested. + { + if (CFDictionaryContainsKey(LoginItemWeAreExaming,HideKey) == false) + { + CFRelease(ArrayOfLoginItemsFixed); + return(NULL); //returning null since LoginItems are corrupted or in a non-reconized format + } + + //Here we get a copy of the HideKey as a CFBooleanRef (a CF boolean). We get the info with a call to CFDictionaryGetValue. + //First Argument: Dictionary to pull the boolean value from (Note that LoginItems are stored as CFDictionaries) + //Second Argument: The key to look up in this case the "hide" key. + HideValue = CFDictionaryGetValue(LoginItemWeAreExaming,HideKey); + + if (HideValue == kCFBooleanTrue) + { + //we set the returnCharacterArray equal to "true" this will be the return value + strcpy(ReturnCharacterArray, "true"); + StringToReturn = (char*) ReturnCharacterArray; + } + else if (HideValue == kCFBooleanFalse) + { + //we set the returnCharacterArray equal to "false" this will be the return value + strcpy(ReturnCharacterArray, "false"); + StringToReturn = (char*) ReturnCharacterArray; + } + else //here we have an invalid HideValue. Thus we give up and return error condition (NULL). + { + CFRelease(ArrayOfLoginItemsFixed); + return(NULL); //returning null since LoginItems are corrupted or in a non-reconized format + } + + } //end kHideInfo section of the routine. + + CFRelease(ArrayOfLoginItemsFixed); + return(StringToReturn); +} + +/***************************************************************************************************/ +// GetCountOfLoginItems +//**************************************************************************************************/ +// This function will return the number of LoginItems for the user requested. +//**************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want the number of LoginItems for. The two alternatives are: kCurrentUser which lists the +// LoginItems which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// +// Output Parameters: +// Return -> This function returns the number of LoginItems for the user requested as a signed integer. +//**************************************************************************************************/ + +int GetCountOfLoginItems(CFStringRef WhosPreferencesToList) +{ + CFArrayRef ArrayOfLoginItemsFixed; + CFStringRef PreferenceName, MainKeyName; + int ValueToReturn = -1; + + + //doing sanity check on the name of the user passed in. Note we can use direct compairson because the pointer values and memory values should be identical to the constants. + if ((WhosPreferencesToList != kCurrentUser) && (WhosPreferencesToList != kAllUsers)) + { + return(0); + } + + //We need the name of the Application to look up in order look up the LoginItem list. In this the name is loginwindow.plist + PreferenceName = CFSTR(kAppStr); //Note: CFString constants do not need to be released. + + //The name of the main or first key referenced in the preference file. In this case it is: AutoLaunchedApplicationDictionary + MainKeyName = CFSTR(kKeyStr); //Note: CFString constants do not need to be released. + + //Getting the array of LoginItems from the LoginItems preference file. + //Parameters: + //First Parameter: The key used to look up the array information. + //Second Parameter:Name of the preference Item (loginwindow.plist in this case), + //Third Parameter: Which user(s) will be effected. We either want the current user (kCurrentUser) or all users (kAllUsers) + //Fourth Parameter: We set this to anyhost because LoginItems always make use of Anyhost. + //Note: The return value will be null if the preference currently does not exist. + //Note that the structure returned must be released later. + + ArrayOfLoginItemsFixed = CFPreferencesCopyValue(MainKeyName, PreferenceName, WhosPreferencesToList, kCFPreferencesAnyHost); + + //If the preference loginwindow.plist doesn't exist (ArrayOfLoginItemsFixed == null) then we know the size of the array is zero. + if( ArrayOfLoginItemsFixed == NULL) //handling case where no LoginItems exist and can't do any lookups. + { + return(0); //number of LoginItems is zero. + } + + ValueToReturn = (int) CFArrayGetCount(ArrayOfLoginItemsFixed); + + CFRelease(ArrayOfLoginItemsFixed); + return(ValueToReturn); +} + +/***************************************************************************************************/ +// RemoveLoginItemAtIndex +//**************************************************************************************************/ +// This function will remove the LoginItem at the given index for the user specified. +//**************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to remove the LoginItem from. The two alternatives are: kCurrentUser which removes login +// items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// Second Parameter (LoginItemIndex) -> An integer representing the LoginItem index of the LoginItem you want removed. +// It is assumed that you will look up the LoginItems using a couple ReturnLoginItemPropertyAtIndex calls +// which will allow you to know which LoginItem you want to remove by index. Note that the LoginItems are +// stored as an array indexed from 0 to N-1 where N is the number of LoginItems. Note that if an invalid +// index is passed then you will get a return value of false indicating error status. +// +// Output Parameters: +// Return -> This function a boolean true if the LoginItem was successfully removed. This function returns false if +// the LoginItem could not be removed (or if it was not found). *Note that when you remove a LoginItem +// from the list of LoginItems the index of all LoginItems following the removed item will be +// deincremented by one. This means there will never be gaps in the list of LoginItems (i.e. empty slots +// in the array of LoginItems). +//**************************************************************************************************/ + +Boolean RemoveLoginItemAtIndex(CFStringRef WhosPreferencesToChange, int LoginItemIndex) +{ + CFArrayRef ArrayOfLoginItemsFixed; + CFStringRef PreferenceName, MainKeyName; + CFMutableArrayRef ArrayOfLoginItemsModifiable; + Boolean Success; + + //Doing a sanity check on the LoginItem index. The LoginItem index can't be smaller than zero and can't be larger than the length of the array (Number of LoginItems - 1). + if ((LoginItemIndex < 0) || (LoginItemIndex > (GetCountOfLoginItems(WhosPreferencesToChange) - 1) )) + { + return(false); + } + + //doing sanity check on the name of the user passed in. Note we can use direct compairson because the pointer values and memory values should be identical to the constants. + if ((WhosPreferencesToChange != kCurrentUser) && (WhosPreferencesToChange != kAllUsers)) + { + return(false); + } + + //We need the name of the Application to look up in order look up the LoginItem list. In this the name is loginwindow.plist + PreferenceName = CFSTR(kAppStr); //Note: CFString constants do not need to be released. + + //The name of the main or first key referenced in the preference file. In this case it is: AutoLaunchedApplicationDictionary + MainKeyName = CFSTR(kKeyStr); //Note: CFString constants do not need to be released. + + //Getting the array of LoginItems from the LoginItems preference file. We will then remove the LoginItem in question from the CFArray and write the preferences back to disk. + //Parameters: + //First Parameter: The key used to look up the array information. + //Second Parameter:Name of the preference Item (loginwindow.plist in this case), + //Third Parameter: Which user(s) will be effected. We either want the current user (kCurrentUser) or all users (kAllUsers) + //Fourth Parameter: We set this to anyhost because LoginItems always make use of Anyhost. + //Note: The return value will be null if the preference currently does not exist. + //Note that the structure returned must be released later. + + ArrayOfLoginItemsFixed = CFPreferencesCopyValue(MainKeyName, PreferenceName, WhosPreferencesToChange, kCFPreferencesAnyHost); + + //If the preference loginwindow.plist doesn't exist (ArrayOfLoginItemsFixed == null) then we know the size of the array is zero. This means that no LoginItems can be removed. In this case we fail and give up. + if( ArrayOfLoginItemsFixed == NULL) //handling case where no LoginItems exist and can't do any lookups. + { + return(false); //returning null since there are no items to return information on + } + + //We want to get a modifiable version of the LoginItems. The modifiable version is where we will make all our changes before saving the LoginItems back to disk. + //First Parameter: using default CFAllocator. + //Second Paramater: want a non-bounded array so set this parameter to 0. This prevents the system from limiting the size of the array we want to use. + //Third Parameter: copy of the original list of LoginItems (the fixed list from before). + ArrayOfLoginItemsModifiable = CFArrayCreateMutableCopy(NULL,0,ArrayOfLoginItemsFixed); + + //If this operation failed then we release allocated structures and give up + if (ArrayOfLoginItemsModifiable == NULL) + { + CFRelease(ArrayOfLoginItemsFixed); + return(false); + } + + //We are removing the selected LoginItem to the list of LoginItems. + //First parameter: CFArray (our LoginItem array) which we want to remove a value. + //Second paramter: the index of the LoginItem we want to remove. Note that we convert the integer to a CFindex which is really just a signed integer. + CFArrayRemoveValueAtIndex(ArrayOfLoginItemsModifiable, (CFIndex) LoginItemIndex); + + //Here we write the settings back to the preference stored in memory. + //Parameters: + //First Parameter: The key used to look up the array information. + //Second Parameter: The LoginItems list to write out to disk. + //Third Parameter:Name of the preference Item (loginwindow preference in this case), + //Fourth Parameter: Which user(s) will be effected. We either want the current user (kCurrentUser) or all users (kAllUsers) + //Fifth Parameter: We set this to anyhost since LoginItems always use anyhost. + CFPreferencesSetValue(MainKeyName,ArrayOfLoginItemsModifiable,PreferenceName, WhosPreferencesToChange, kCFPreferencesAnyHost); + + //Here we write the preference file in memory back to the hard disk. + Success = CFPreferencesSynchronize(PreferenceName, WhosPreferencesToChange, kCFPreferencesAnyHost); + + //If this operation failed then we release allocated structures and give up + if (Success == false) + { + CFRelease(ArrayOfLoginItemsModifiable); + CFRelease(ArrayOfLoginItemsFixed); + return(false); + } + + //Releasing all the data structures which need releasing. + CFRelease(ArrayOfLoginItemsModifiable); + CFRelease(ArrayOfLoginItemsFixed); + + return(true); //we return true because all operations succeeded which means the LoginItems were successfully updated. + +} + +/***************************************************************************************************/ +// PrintOutLoginItemAtIndex +//**************************************************************************************************/ +// This function will print out the LoginItem at the specified index +//**************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to print the LoginItem from. The two alternatives are: kCurrentUser which removes login +// items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// Second Parameter (LoginItemIndex) -> An integer representing the LoginItem index of the LoginItem you want to +// print. Note that the LoginItems are stored as an array indexed from 0 to N-1 where N is the number of +// LoginItems. Note that if an invalid index is passed then you will get a return value of false +// indicating error status. +// +// Output Parameters: +// Return -> This function a boolean true if the LoginItem was successfully printed. +//**************************************************************************************************/ + +Boolean PrintOutLoginItemAtIndex(CFStringRef WhosPreferencesToList, int LoginItemIndex) +{ + + char* StringToPrint; + + //doing sanity check on the name of the user passed in. Note we can use direct compairson because the pointer values and memory values should be identical to the constants. + if ((WhosPreferencesToList != kCurrentUser) && (WhosPreferencesToList != kAllUsers)) + { + return(false); + } + + //doing sanity check on index passed in. Return false if index isn't valid. + if ((LoginItemIndex < 0) || (LoginItemIndex > GetCountOfLoginItems(WhosPreferencesToList))) + { + return(false); + } + + StringToPrint = ReturnLoginItemPropertyAtIndex(WhosPreferencesToList, kFullPathInfo, LoginItemIndex); + + if (StringToPrint == NULL) + { + return(false); + } + + printf("\tFull path to App: %s\n", StringToPrint); + + StringToPrint = ReturnLoginItemPropertyAtIndex(WhosPreferencesToList, kHideInfo, LoginItemIndex); + + if (StringToPrint == NULL) + { + return(false); + } + + printf("\tHide Info: %s\n", StringToPrint); + + StringToPrint = ReturnLoginItemPropertyAtIndex(WhosPreferencesToList, kApplicationNameInfo, LoginItemIndex); + + if (StringToPrint == NULL) + { + return(false); + } + + printf("\tExecutable Name: %s\n", StringToPrint); + + return(true); +} + +/***************************************************************************************************/ +// PrintOutAllLoginItems +//**************************************************************************************************/ +// This function will print out all the LoginItems for the specified user +//**************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to print the LoginItems from. The two alternatives are: kCurrentUser which removes login +// items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// +// Output Parameters: +// Return -> This function a boolean true if the LoginItem was successfully printed. +//**************************************************************************************************/ + +Boolean PrintOutAllLoginItems(CFStringRef WhosPreferencesToList) +{ + int NumberOfLoginItems, Counter; + Boolean Success; + + //doing sanity check on the name of the user passed in. Note we can use direct compairson because the pointer values and memory values should be identical to the constants. + if ((WhosPreferencesToList != kCurrentUser) && (WhosPreferencesToList != kAllUsers)) + { + return(false); + } + + NumberOfLoginItems = GetCountOfLoginItems(WhosPreferencesToList); + + if (NumberOfLoginItems == 0) + { + printf("LoginItems are Empty (i.e. there are no LoginItems)\n"); + } + + for (Counter = 0 ; Counter < NumberOfLoginItems ; Counter++) + { + printf("LoginItem Index %d:\n", Counter); + Success = PrintOutLoginItemAtIndex(WhosPreferencesToList, Counter); + + if (Success == false) //if couldn't print the specified index then we give up. + {return(false);} + } + + return(true); +} + +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to print the number of LoginItems from. The two alternatives are: kCurrentUser +// which removes login items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// +// Output Parameters: +// Return -> True if number of login items successfully printed. false otherwise. +//**************************************************************************************************/ +Boolean PrintNumberOfLoginItems(CFStringRef WhosPreferencesToList) +{ + + //doing sanity check on the name of the user passed in. Note we can use direct compairson because the pointer values and memory values should be identical to the constants. + if ((WhosPreferencesToList != kCurrentUser) && (WhosPreferencesToList != kAllUsers)) + { + return(false); + } + + printf("The number of LoginItems is: %d", GetCountOfLoginItems(WhosPreferencesToList)); + return(true); +} + + diff --git a/mac_installer/LoginItemAPI.h b/mac_installer/LoginItemAPI.h new file mode 100755 index 0000000000..5f865865b4 --- /dev/null +++ b/mac_installer/LoginItemAPI.h @@ -0,0 +1,222 @@ +/* + File: LoginItemAPI.h + + Copyright: © 2000-2003 by Apple Computer, Inc., all rights reserved. + + Bugs?: For bug reports, consult the following page on + the World Wide Web: + + http://developer.apple.com/bugreporter/ + +*/ + +#if defined(__MWERKS__) //for use with CodeWarrior +# include //making a carbon project so need carbon.h +# include //this is used for window control in CodeWarrior +#else //for use with project builder +# import //This is the only ProjectBuilder include we really needed +# import //This is where all the CFPreference APIs come from. +# import //used when printing out to standard output +#endif + +//These are used as constants for the second argument to AddLoginItemWithPropertiesToUser. Either the application is hidden on launch or shows up this property decides this. +#define kHideOnLaunch true +#define kDoNotHideOnLaunch false + +//These are used as constants for the third argument to AddLoginItemWithPropertiesToUser. You can either set the properties of the current user or all the users on the system (with kAllUsers). +#define kCurrentUser kCFPreferencesCurrentUser +#define kAllUsers kCFPreferencesAnyUser + +//#define kAppStr "loginwindow" +#define kAppStr "loginwindow" +//The preference name where LoginItem information is stored. We are actually writing to the file loginwindow.plist in either /Users/Library/Preferences/ directory (for the kCurrentUser) or the /Library/Preferences folder (for All Users). Note that if you want to install this for all users on the system then you must be root/admin to do so. If you need to know how to become root check out the sample code: "AuthSample" on the developer.apple.com website + +#define kKeyStr "AutoLaunchedApplicationDictionary" //The required "special" key for accessing LoginItem information. + +//defining types which are used as the request types into the function GetListOfLoginItems. kFullPathInfo causes the routine to return the full path as a character string, kApplicationNameInfo causes just the application or alias name to be returned, kHideInfo returns if the application is hidden on launch or not. + +#define kFullPathInfo 1 +#define kApplicationNameInfo 2 +#define kHideInfo 3 + +//This is the character array size used by GetListOfLoginItems +#define kLoginItemInfoLength 1025 + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************************************/ +// AddLoginItemWithPropertiesToUser +/***************************************************************************************************/ +// This function will add a LoginItem to the list of LoginItems when called. The properties +// given to the new LoginItem are passed when calling the function. Note that *no* check is made +// when adding the LoginItem to ensure that the path points to a valid application. Note that the LoginItem +// Is always added to the *end* of the list of LoginItems. +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToChange) -> A constant which represents which users preferences +// we want to change. In this case there are two alternatives: kCurrentUser which +// changes the preferences of the current user. The second alternative is kAllUsers. +// The kAllUsers LoginItems are launched for all users on the system. You must be root +// or admin to use the kAllUsers option. +// Second Parameter (AbsolutePath) -> The absolute path of the application to be launched +// expressed as a Standard C string. (example: "/Applications/Clock") +// Third Parameter (HidetheApplicationOnStartup) -> A value representing if you want +// your application to be hidden at login time. kHideOnLaunch if you want the +// application to be hidden after it is launched. If you want the application to show +// up normally use be hidden use kDoNotHideOnLaunch +// +// Output Parameters: +// Return -> This function returns a boolean value representing if the function was successful. +// The function returns true if the LoginItem was successfully added. False if +// otherwise. No additional error codes are returned. +// Other Notes: This code doesn't work properly if more than one application is attempting to write to +// the LoginItems preference at once. +// Also no check is made to ensure that what you are adding to the LoginItem list isn't a +// duplicate. If there is a duplicate however only one instance of the application is launched +/***************************************************************************************************/ + +Boolean AddLoginItemWithPropertiesToUser(CFStringRef WhosPreferencesToChange, const char* AbsolutePath, Boolean HidetheApplicationOnLaunch); + +/***************************************************************************************************/ +// ReturnLoginItemPropertyAtIndex +/***************************************************************************************************/ +// This function will return the list of LoginItems as a CFArray. +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to examine. The two alternatives are: kCurrentUser which lists the LoginItems +// which are specific to that user (these are preferences found in /Users//Library/Preferences) +// and kAnyUsers which lists LoginItems which are common to all users on the system (these +// preferences are found in /Library/Preferences/). +// Second Parameter (RequestType) -> A constant representing which type of request for information you are making. +// There are currently three request types. kFullPathInfo which causes this routine to return the +// absolute path to the LoginItem which is stored as a C String (example return value: +// "/Applications/Clock.app"). Second alternative is kApplicationNameInfo which causes the routine to +// return the name of the application as a C string (example return value: "Clock.app"). Third +// alternative is kHideInfo which causes the routine to return the hide current status as a C string. +// The two return types possible are the C Strings "Hide" and "DoNotHide" (example return value: "Hide") +// Third Parameter (LoginItemIndex) -> An integer representing the LoginItem index. Note that the LoginItems are +// stored as an array indexed from 0 to N-1 where N is the number of LoginItems. Note that if an invalid +// index is passed then you will get a return value of NULL indicating error status. +// +// Output Parameters: +// Return -> This function returns a value of NULL if an error has occurred (likely caused by attempting to index an +// invalid LoginItemIndex). If no error has occurred then a C String is returned which represents the data +// requested on the LoginItem at the index given. The three return types are: +// 1) For a kFullPathInfo request the absolute path of the LoginItem is returned (example: +// "/Applications/TextEdit"). 2) For a kApplicationNameInfo request only the LoginItem name is returned +// with no path (example: "TextEdit"). 3) For a kHideInfo request either the C string "Hide" is returned +// if LoginItem is hidden on launch or the C string value is "DoNotHide" if the LoginItem isn't hidden on +// launch +// Other Notes: The actual indexing of the LoginItem array starts at zero and goes up to N-1 where N is the number of +// LoginItems. Also, the order that the LoginItems are listed in the array is consistent with the ordering +// of the LoginItems within the preference file. Note that the ordering of the LoginItems in the array +// *does not* correspond to the order which the LoginItems are launched. The order which LoginItems are +// launched are determined by OSX at Login time and is based on what launch order would be most efficent. +/***************************************************************************************************/ + +char* ReturnLoginItemPropertyAtIndex(CFStringRef WhosPreferencesToList, int RequestType, int LoginItemIndex); + +/***************************************************************************************************/ +// GetCountOfLoginItems +/***************************************************************************************************/ +// This function will return the number of LoginItems for the user requested. +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want the number of LoginItems for. The two alternatives are: kCurrentUser which lists the +// LoginItems which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// +// Output Parameters: +// Return -> This function returns the number of LoginItems for the user requested as a signed integer. +/***************************************************************************************************/ + +int GetCountOfLoginItems(CFStringRef WhosPreferencesToList); + +/***************************************************************************************************/ +// RemoveLoginItemAtIndex +/***************************************************************************************************/ +// This function will remove the LoginItem at the given index for the user specified. +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to remove the LoginItem from. The two alternatives are: kCurrentUser which removes login +// items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// Second Parameter (LoginItemIndex) -> An integer representing the LoginItem index of the LoginItem you want removed. +// It is assumed that you will look up the LoginItems using a couple ReturnLoginItemPropertyAtIndex calls +// which will allow you to know which LoginItem you want to remove by index. Note that the LoginItems are +// stored as an array indexed from 0 to N-1 where N is the number of LoginItems. Note that if an invalid +// index is passed then you will get a return value of false indicating error status. +// +// Output Parameters: +// Return -> This function a boolean true if the LoginItem was successfully removed. This function returns false if +// the LoginItem could not be removed (or if it was not found). *Note that when you remove a LoginItem +// from the list of LoginItems the index of all LoginItems following the removed item will be +// deincremented by one. This means there will never be gaps in the list of LoginItems (i.e. empty slots +// in the array of LoginItems). +/***************************************************************************************************/ + +Boolean RemoveLoginItemAtIndex(CFStringRef WhosPreferencesToChange, int LoginItemIndex); + +/***************************************************************************************************/ +// PrintOutLoginItemAtIndex +/***************************************************************************************************/ +// This function will print out the LoginItem at the specified index +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to print the LoginItem from. The two alternatives are: kCurrentUser which removes login +// items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// Second Parameter (LoginItemIndex) -> An integer representing the LoginItem index of the LoginItem you want to +// print. Note that the LoginItems are stored as an array indexed from 0 to N-1 where N is the number of +// LoginItems. Note that if an invalid index is passed then you will get a return value of false +// indicating error status. +// +// Output Parameters: +// Return -> This function a boolean true if the LoginItem was successfully printed. +/***************************************************************************************************/ + +Boolean PrintOutLoginItemAtIndex(CFStringRef WhosPreferencesToList, int LoginItemIndex); + +/***************************************************************************************************/ +// PrintOutAllLoginItems +/***************************************************************************************************/ +// This function will print out all the LoginItems for the specified user +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to print the LoginItems from. The two alternatives are: kCurrentUser which removes login +// items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// +// Output Parameters: +// Return -> This function a boolean true if the LoginItem was successfully printed. +/***************************************************************************************************/ + +Boolean PrintOutAllLoginItems(CFStringRef WhosPreferencesToList); + +/***************************************************************************************************/ +// Input Parameters: +// First Parameter (WhosPreferencesToList) -> A constant representing which users preferences +// you want to print the number of LoginItems from. The two alternatives are: kCurrentUser +// which removes login items for the which are specific to that user (these are preferences found in +// /Users//Library/Preferences) and kAnyUsers which lists LoginItems which are common to all +// users on the system (these preferences are found in /Library/Preferences/). +// +// Output Parameters: +// Return -> True if number of login items successfully printed. false otherwise. +/***************************************************************************************************/ +Boolean PrintNumberOfLoginItems(CFStringRef WhosPreferencesToList); + +#ifdef __cplusplus +} +#endif diff --git a/mac_installer/PostInstall.cpp b/mac_installer/PostInstall.cpp new file mode 100755 index 0000000000..fc3f80a8b2 --- /dev/null +++ b/mac_installer/PostInstall.cpp @@ -0,0 +1,111 @@ +// Berkeley Open Infrastructure for Network Computing +// http://boinc.berkeley.edu +// Copyright (C) 2005 University of California +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// either version 2.1 of the License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// To view the GNU Lesser General Public License visit +// http://www.gnu.org/copyleft/lesser.html +// or write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +/* PostInstall.c */ + +#include + +#include // getlogin +#include // getpwname, getpwuid, getuid +#include // getpwname, getpwuid, getuid +#include // waitpid + +#include "LoginItemAPI.h" //please take a look at LoginItemAPI.h for a explanation of the routines available to you. + +void Initialize(void); /* function prototypes */ +static OSErr QuitAppleEventHandler(const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon); + +void SetUIDBackToUser (void); + +Boolean gQuitFlag = false; /* global */ + +int main(int argc, char *argv[]) +{ + char *p, *q; + Boolean Success; + int NumberOfLoginItems, Counter; + + Initialize(); + + Success = false; + +// ***************************************************************************************** +// Everything after this REQUIRES us to be setuid to the login user's user ID +// ***************************************************************************************** + // Installer is running as root. We must setuid back to the logged in user + // in order to add a startup item to the user's login preferences + + SetUIDBackToUser (); + + NumberOfLoginItems = GetCountOfLoginItems(kCurrentUser); + + // Search existing login items in reverse order, deleting any duplicates of ours + for (Counter = NumberOfLoginItems ; Counter > 0 ; Counter--) + { + p = ReturnLoginItemPropertyAtIndex(kCurrentUser, kApplicationNameInfo, Counter-1); + q = p; + while (*q) + { + // It is OK to modify the returned string because we "own" it + *q = toupper(*q); // Make it case-insensitive + q++; + } + + if (strcmp(p, "BOINCMANAGER.APP") == 0) + Success = RemoveLoginItemAtIndex(kCurrentUser, Counter-1); + } + + Success = AddLoginItemWithPropertiesToUser(kCurrentUser, + "/Applications/BOINCManager.app", kDoNotHideOnLaunch); + + return 0; +} + + +void SetUIDBackToUser (void) +{ + char *p; + uid_t login_uid; + passwd *pw; + + p = getlogin(); + pw = getpwnam(p); + login_uid = pw->pw_uid; + + setuid(login_uid); +} + + +void Initialize() /* Initialize some managers */ +{ + OSErr err; + + InitCursor(); + + err = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false ); + if (err != noErr) + ExitToShell(); +} + +static OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) +{ + gQuitFlag = true; + + return noErr; +} diff --git a/mac_installer/ReadMe.rtf b/mac_installer/ReadMe.rtf new file mode 100644 index 0000000000..a3a206c3b9 --- /dev/null +++ b/mac_installer/ReadMe.rtf @@ -0,0 +1,35 @@ +{\rtf1\mac\ansicpg10000\cocoartf102 +{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww9000\viewh9000\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc + +\f0\b\fs28 \cf0 Macintosh BOINCManager Version 3.40 Release Notes\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural + +\f1\b0\fs24 \cf0 \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc +\cf0 http://boinc.berkeley.edu/\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural +\cf0 \ +BOINCManager requires Macintosh OS X version 10.2 or greater.\ +\ +Although this installer adds the BOINC screen saver to your system, it does not change your screen saver settings. To select BOINC as your screen saver, use the Screen Saver or Screen Effects panel in the System Preferences (accessible from the Apple menu). \ +\ +It may take a minute after the screen saver starts before the science application graphics appear.\ +\ +Note: you may not be able to exit the BOINC screen saver by moving the mouse; you may need to press the mouse button or press any key on the keyboard to exit. \ +\ +The installer places two items onto your hard drive: BOINCManager.app in your /Applications folder and BOINCSaver.saver in your /Library/Screen Savers folder. \ +\ +It also sets BOINCManager as one of the items to automatically start whenever the user is logged in. You can add or remove Startup Items by using the Accounts Pane in the System Preferences (accessible from the Apple menu). \ +\ +The installer creates the BOINC Data folder in your /Library/Application Support folder. If you have previously been running BOINC in a different folder, copy your data into this folder. \ +\ +All users who log in on the same Macintosh will share one set of BOINC data, ensuring that work units are processed in the most timely manner. However, the installer sets BOINCManager as a Startup item only for the user who ran the installer. To have BOINCManager start automatically when other users log in, add it to each user's Startup Items as described above.\ +\ +You can move BOINCManager to any folder you wish. If you do so, you will need to update the information in each user's Startup Items. In most cases, the BOINC screen saver should still work properly. If it does not, move BOINCManager back to the Applications folder.\ +\ +The installer sets the "setuid" permission flag for the BOINCManager, which allows it to write to the shared BOINC Data regardless of which user is logged in. If you copy BOINCManager to your computer without using the installer, some users may not be able to run it properly.\ +\ +} \ No newline at end of file diff --git a/mac_installer/postinstall b/mac_installer/postinstall new file mode 100644 index 0000000000..9b94facb38 --- /dev/null +++ b/mac_installer/postinstall @@ -0,0 +1,11 @@ +#!/bin/csh + +## +# post-Install Script for Macintosh BOINC Manager for OS X revised 4/26/05 +## + +cd "$1" +/ Run the Postinstall Application +Contents/Resources/PostInstall.app/Contents/MacOS/PostInstall + +chmod -R a+s /Applications/BOINCManager.app diff --git a/mac_installer/postupgrade b/mac_installer/postupgrade new file mode 100755 index 0000000000..f99e866f8e --- /dev/null +++ b/mac_installer/postupgrade @@ -0,0 +1,11 @@ +#!/bin/csh + +## +# post-Upgrade Script for Macintosh BOINC Manager for OS X revised 4/26/05 +## + +cd "$1" +/ Run the Postinstall Application +Contents/Resources/PostInstall.app/Contents/MacOS/PostInstall + +chmod -R a+s /Applications/BOINCManager.app