/* * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include "RepeatingAutoWake.h" #include "PrivateLib.h" #include "AutoWakeScheduler.h" /* * These are the days of the week as provided by * CFAbsoluteTimeGetDayOfWeek() * enum { kCFMonday = 1, kCFTuesday = 2, kCFWednesday = 3, kCFThursday = 4, kCFFriday = 5, kCFSaturday = 6, kCFSunday = 7 }; * * In the "days of the week" bitmask, this is the key... * enum { kBitMaskMonday = 0, kBitMaskTuesday = 1, kBitMaskWednesday = 2, kBitMaskThursday = 3, kBitMaskFriday = 4, kBitMaskSaturday = 5, kBitMaskSunday = 6 }; */ static CFDictionaryRef repeatingPowerOff = 0; static CFDictionaryRef repeatingPowerOn = 0; static bool is_valid_repeating_dictionary(CFDictionaryRef event) { CFNumberRef tmp_num; CFStringRef tmp_str; if(NULL == event) return true; if(!isA_CFDictionary(event)) return false; tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTimeKey)); if(!isA_CFNumber(tmp_num)) return false; tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMDaysOfWeekKey)); if(!isA_CFNumber(tmp_num)) return false; tmp_str = (CFStringRef)CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTypeKey)); if(!isA_CFString(tmp_str)) return false; if( !CFEqual(tmp_str, CFSTR(kIOPMAutoSleep)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoShutdown)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoWakeOrPowerOn)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoPowerOn)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoWake)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoRestart)) ) { return false; } return true; } static int getRepeatingDictionaryMinutes(CFDictionaryRef event) { int val; CFNumberRef tmp_num; tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTimeKey)); CFNumberGetValue(tmp_num, kCFNumberIntType, &val); return val; } static int getRepeatingDictionaryDayMask(CFDictionaryRef event) { int val; CFNumberRef tmp_num; tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMDaysOfWeekKey)); CFNumberGetValue(tmp_num, kCFNumberIntType, &val); return val; } static CFStringRef getRepeatingDictionaryType(CFDictionaryRef event) { CFStringRef return_string; if(!event) { return CFSTR(""); } return_string = isA_CFString( CFDictionaryGetValue( event, CFSTR(kIOPMPowerEventTypeKey)) ); // prevent unexpected crashes by returning an empty string rather than NULL if(!return_string) { return CFSTR(""); } return return_string; } // returns false if event occurs at 8PM and now it's 10PM // returns true if event occurs at 8PM, now it's 9AM static bool upcomingToday(CFDictionaryRef event, int today_cf) { static const int kAllowScheduleWindowSeconds = 5; uint32_t secondsToday; int secondsScheduled; int days_mask; if(!event) return false; // Determine if the scheduled event falls on today's day of week days_mask = getRepeatingDictionaryDayMask(event); if(!(days_mask & (1 << (today_cf-1)))) return false; // get gregorian date for right now int hour, minute; CFCalendarDecomposeAbsoluteTime(_gregorian(), CFAbsoluteTimeGetCurrent(), "Hm", &hour, &minute); secondsToday = 60 * (hour*60 + minute); secondsScheduled = 60 * getRepeatingDictionaryMinutes(event); // Initially, we required a 2 minute safety window before scheduling the next // power event. Now, we throw caution to the wind and try a 5 second window. // Lost events will simply be lost events. if(secondsScheduled >= (secondsToday + kAllowScheduleWindowSeconds)) return true; else return false; } // daysUntil // returns 0 if the event is upcoming today // otherwise returns days until next repeating event, in range 1-7 static int daysUntil(CFDictionaryRef event, int today_cf_day_of_week) { int days_mask = getRepeatingDictionaryDayMask(event); int check = today_cf_day_of_week % 7; if(0 == days_mask) return -1; if(upcomingToday(event, today_cf_day_of_week)) return 0; // Note: CF days start counting at 1, the bit mask starts counting at 0. // Therefore, since we're tossing the CF day of week into a variable (check) // that we're checking the bitmask with, "check" effectively refers // to tomorrow, whlie today_cf_day_of_week refers to today. while(!(days_mask & (1<