1/* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23// Disable symbol overrides so that we can use system headers. 24#define FORBIDDEN_SYMBOL_ALLOW_ALL 25 26#include "common/system.h" 27#include "backends/updates/macosx/macosx-updates.h" 28 29#ifdef USE_SPARKLE 30#include "common/translation.h" 31#include "common/config-manager.h" 32 33#include <Cocoa/Cocoa.h> 34#include <Sparkle/Sparkle.h> 35 36#include <AvailabilityMacros.h> 37 38SUUpdater *sparkleUpdater; 39 40/** 41 * Sparkle is a software update framework for Mac OS X which uses appcasts for 42 * release information. Appcasts are RSS-like XML feeds which contain information 43 * about the most current version at the time. If a new version is available, the 44 * user is presented the release-notes/changes/fixes and is asked if he wants to 45 * update, and if yes the Sparkle framework downloads a signed update package 46 * from the server and automatically installs and restarts the software. 47 * More detailed information is available at the following address: 48 * http://sparkle.andymatuschak.org/ 49 * 50 */ 51MacOSXUpdateManager::MacOSXUpdateManager() { 52 NSBundle* mainBundle = [NSBundle mainBundle]; 53 54 NSString *version = [mainBundle objectForInfoDictionaryKey:(__bridge NSString *)kCFBundleVersionKey]; 55 if (!version || [version isEqualToString:@""]) { 56 warning("Running not in bundle, skipping Sparkle initialization"); 57 58 sparkleUpdater = nullptr; 59 return; 60 } 61 62 NSMenuItem *menuItem = [[NSApp mainMenu] itemAtIndex:0]; 63 NSMenu *applicationMenu = [menuItem submenu]; 64 65 // Init Sparkle 66 sparkleUpdater = [SUUpdater sharedUpdater]; 67 68 NSString* feedbackURL = [mainBundle objectForInfoDictionaryKey:@"SUFeedURL"]; 69 70 // Set appcast URL 71 [sparkleUpdater setFeedURL:[NSURL URLWithString:feedbackURL]]; 72 73 // Get current encoding 74 CFStringRef encStr = CFStringCreateWithCString(NULL, TransMan.getCurrentCharset().c_str(), kCFStringEncodingASCII); 75 CFStringEncoding stringEncoding = CFStringConvertIANACharSetNameToEncoding(encStr); 76 CFRelease(encStr); 77 78 // Add "Check for Updates..." menu item 79 CFStringRef title = CFStringCreateWithCString(NULL, _("Check for Updates..."), stringEncoding); 80 NSMenuItem *updateMenuItem = [applicationMenu insertItemWithTitle:(NSString *)title action:@selector(checkForUpdates:) keyEquivalent:@"" atIndex:1]; 81 CFRelease(title); 82 83 // Set the target of the new menu item 84 [updateMenuItem setTarget:sparkleUpdater]; 85 86 // Finally give up our references to the objects 87 [menuItem release]; 88 89 if (!ConfMan.hasKey("updates_check") 90 || ConfMan.getInt("updates_check") == Common::UpdateManager::kUpdateIntervalNotSupported) { 91 setAutomaticallyChecksForUpdates(kUpdateStateDisabled); 92 } else { 93 setAutomaticallyChecksForUpdates(kUpdateStateEnabled); 94 setUpdateCheckInterval(normalizeInterval(ConfMan.getInt("updates_check"))); 95 } 96} 97 98MacOSXUpdateManager::~MacOSXUpdateManager() { 99 [sparkleUpdater release]; 100} 101 102void MacOSXUpdateManager::checkForUpdates() { 103 if (sparkleUpdater == nullptr) 104 return; 105 106 [sparkleUpdater checkForUpdates:nil]; 107} 108 109void MacOSXUpdateManager::setAutomaticallyChecksForUpdates(UpdateManager::UpdateState state) { 110 if (state == kUpdateStateNotSupported) 111 return; 112 113 if (sparkleUpdater == nullptr) 114 return; 115 116 [sparkleUpdater setAutomaticallyChecksForUpdates:(state == kUpdateStateEnabled ? YES : NO)]; 117} 118 119Common::UpdateManager::UpdateState MacOSXUpdateManager::getAutomaticallyChecksForUpdates() { 120 if (sparkleUpdater == nullptr) 121 return kUpdateStateDisabled; 122 123 if ([sparkleUpdater automaticallyChecksForUpdates]) 124 return kUpdateStateEnabled; 125 else 126 return kUpdateStateDisabled; 127} 128 129void MacOSXUpdateManager::setUpdateCheckInterval(int interval) { 130 if (sparkleUpdater == nullptr) 131 return; 132 133 if (interval == kUpdateIntervalNotSupported) 134 return; 135 136 interval = normalizeInterval(interval); 137 138 [sparkleUpdater setUpdateCheckInterval:(NSTimeInterval)interval]; 139} 140 141int MacOSXUpdateManager::getUpdateCheckInterval() { 142 if (sparkleUpdater == nullptr) 143 return kUpdateIntervalOneDay; 144 145 // This is kind of a hack but necessary, as the value stored by Sparkle 146 // might have been changed outside of ScummVM (in which case we return the 147 // default interval of one day) 148 149 UpdateInterval updateInterval = (UpdateInterval)[sparkleUpdater updateCheckInterval]; 150 switch (updateInterval) { 151 case kUpdateIntervalOneDay: 152 case kUpdateIntervalOneWeek: 153 case kUpdateIntervalOneMonth: 154 return updateInterval; 155 156 default: 157 // Return the default value (one day) 158 return kUpdateIntervalOneDay; 159 } 160} 161 162bool MacOSXUpdateManager::getLastUpdateCheckTimeAndDate(TimeDate &t) { 163 if (sparkleUpdater == nullptr) 164 return false; 165 166 NSDate *date = [sparkleUpdater lastUpdateCheckDate]; 167#ifdef MAC_OS_X_VERSION_10_10 168 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 169 NSDateComponents *components = [gregorian components:(NSCalendarUnitDay | NSCalendarUnitWeekday) fromDate:date]; 170#else 171 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 172 NSDateComponents *components = [gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:date]; 173#endif 174 175 t.tm_wday = [components weekday]; 176 t.tm_year = [components year]; 177 t.tm_mon = [components month]; 178 t.tm_mday = [components day]; 179 t.tm_hour = [components hour]; 180 t.tm_min = [components minute]; 181 t.tm_sec = [components second]; 182 183 [gregorian release]; 184 185 return true; 186} 187 188#endif 189