autoupdate: add Sparkle framework

This commits brings optionnal linking against Sparkle framework.
This framework is used to autoupdate apps not present in the Mac app store

Refs #75349

Change-Id: I82b14757c106f1282d91e631927057d00989feb7
diff --git a/.gitignore b/.gitignore
index 46f3585..6f0c20c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@
 *.exe
 *.out
 *.app
+Sparkle.framework
 
 # Qt-es
 *.user
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..1db2f94
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "sparkle/Sparkle"]
+	path = sparkle/Sparkle
+	url = https://github.com/sparkle-project/Sparkle.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d16b119..ba0e551 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,14 @@
 ENDIF(POLICY CMP0022)
 
 SET(PROJ_NAME Ring)
-SET(RING_VERSION "0.4.0")
+
+# To build nighlies we need to update RING_VERSION with an optional command line arg
+IF("${RING_VERSION}" STREQUAL "")
+   SET(RING_VERSION "0.4.0")
+ENDIF("${RING_VERSION}" STREQUAL "")
+
+MESSAGE("Building Ring version - " ${RING_VERSION})
+
 SET(RING_VERSION_NAME "Samuel de Champlain")
 SET(BUNDLE_VERSION "Samuel de Champlain - beta")
 
@@ -20,13 +27,43 @@
 FIND_PACKAGE(Qt5Widgets REQUIRED)
 FIND_PACKAGE(LibRingClient REQUIRED)
 
+IF(NOT (${ENABLE_SPARKLE} MATCHES false))
+   MESSAGE("Sparkle auto-update enabled")
+
+   # find_library searches in /Library/Frameworks by default
+   # We add an hint to our custom location
+
+   FIND_LIBRARY(SPARKLE_FRAMEWORK
+                NAMES Sparkle
+                HINTS ${CMAKE_CURRENT_SOURCE_DIR}/sparkle)
+   IF(EXISTS ${SPARKLE_FRAMEWORK})
+      SET(ENABLE_SPARKLE 1 CACHE BOOLEAN "Enable Sparkle")
+      ADD_DEFINITIONS(-DENABLE_SPARKLE=1)
+      MESSAGE("Sparkle is here:" ${SPARKLE_FRAMEWORK})
+      FIND_PATH(SPARKLE_INCLUDE_DIR Sparkle.h HINTS ${SPARKLE_FRAMEWORK}/Headers)
+      MESSAGE("INCLUDE " ${SPARKLE_INCLUDE_DIR})
+      # we need to copy the public key to check the updates
+      SET(PUBLIC_KEY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/sparkle/dsa_pub.pem")
+      IF(EXISTS ${PUBLIC_KEY_PATH})
+         MESSAGE(STATUS "Looking for Public Key - found")
+         SET_SOURCE_FILES_PROPERTIES(${PUBLIC_KEY_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
+         SET(PUBLIC_KEY ${PUBLIC_KEY_PATH})
+      ELSE(EXISTS ${PUBLIC_KEY_PATH})
+         MESSAGE(WARNING "Looking for Public Key - not found")
+         MESSAGE(WARNING "${PUBLIC_KEY_PATH} not found Sparkle Framework will NOT work and may even prevent application from launching. Please consider disabling Sparkle Framework, creating a keypair for testing purposes")
+      ENDIF(EXISTS ${PUBLIC_KEY_PATH})
+   ELSE()
+      MESSAGE(FATAL_ERROR "Sparkle framework not found, build it (see README) or disable Sparkle (-DENABLE_SPARKLE=false)")
+   ENDIF(EXISTS ${SPARKLE_FRAMEWORK})
+ENDIF(NOT (${ENABLE_SPARKLE} MATCHES false))
+
 INCLUDE_DIRECTORIES(SYSTEM ${Qt5Core_INCLUDE_DIRS})
 INCLUDE_DIRECTORIES(SYSTEM ${Qt5MacExtras_INCLUDE_DIRS})
 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
 INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR})
 INCLUDE_DIRECTORIES(${LIB_RING_CLIENT_INCLUDE_DIR})
 
-MESSAGE("LibRingClient is here:" ${LIB_RING_CLIENT_INCLUDE_DIR})
+MESSAGE("LRC is here:" ${LIB_RING_CLIENT_INCLUDE_DIR})
 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
 
 #Files to compile
@@ -142,7 +179,7 @@
   SET(ringclient_XIBS_FOR_EXECUTABLE ${ringclient_XIBS_FOR_EXECUTABLE} ui/${xib}.xib)
 ENDFOREACH()
 
-ADD_EXECUTABLE(${PROJ_NAME} MACOSX_BUNDLE
+SET(TO_ADD 
    ${ringclient_CONTROLLERS}
    ${ringclient_BACKENDS}
    ${ringclient_VIEWS}
@@ -152,6 +189,12 @@
    Credits.rtf
    ${ring_ICONS})
 
+IF(ENABLE_SPARKLE)
+   SET( TO_ADD ${TO_ADD} ${PUBLIC_KEY} ${SPARKLE_FRAMEWORK})
+ENDIF(ENABLE_SPARKLE)
+
+ADD_EXECUTABLE(${PROJ_NAME} MACOSX_BUNDLE ${TO_ADD})
+
 # Follow Xcode hierarchy principles
 SOURCE_GROUP("Controllers" FILES ${ringclient_CONTROLLERS})
 SOURCE_GROUP("Backends" FILES ${ringclient_BACKENDS})
@@ -159,6 +202,9 @@
 SOURCE_GROUP("Classes" FILES ${ringclient_OTHERS})
 SOURCE_GROUP("Resources\\Interface Builder" FILES ${ringclient_XIBS_FOR_EXECUTABLE})
 
+IF(ENABLE_SPARKLE)
+    SOURCE_GROUP("Frameworks" FILES ${SPARKLE_FRAMEWORK})
+ENDIF(ENABLE_SPARKLE)
 
 TARGET_LINK_LIBRARIES( ${PROJ_NAME}
    ${LIB_RING_CLIENT_LIBRARY}
@@ -167,6 +213,10 @@
    ${Qt5Widgets_LIBRARIES}
 )
 
+IF(ENABLE_SPARKLE)
+   TARGET_LINK_LIBRARIES(${PROJ_NAME} ${SPARKLE_FRAMEWORK})
+ENDIF(ENABLE_SPARKLE)
+
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit")
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Cocoa")
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Quartz")
@@ -174,15 +224,15 @@
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AddressBook")
 
 # These variables are specific to our plist and are NOT standard CMake variables
-set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "MainMenu")
-set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication")
+SET(MACOSX_BUNDLE_NSMAIN_NIB_FILE "MainMenu")
+SET(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication")
 
 SET_TARGET_PROPERTIES(${PROJ_NAME} PROPERTIES
         MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/cmake/MacOSXBundleInfo.plist.in
         MACOSX_BUNDLE_GUI_IDENTIFIER "cx.ring"
-        MACOSX_BUNDLE_SHORT_VERSION_STRING ${RING_VERSION_NAME}
+        MACOSX_BUNDLE_SHORT_VERSION_STRING ${RING_VERSION}
         MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJ_NAME} ${RING_VERSION} Nightly"
-        MACOSX_BUNDLE_BUNDLE_VERSION ${RING_VERSION}
+        MACOSX_BUNDLE_BUNDLE_VERSION ${RING_VERSION_NAME}
         MACOSX_BUNDLE_COPYRIGHT "${PROJ_COPYRIGHT}"
         MACOSX_BUNDLE_INFO_STRING "Nightly build of ${PROJ_NAME} ${RING_VERSION} for testing and development"
         MACOSX_BUNDLE_BUNDLE_NAME ${PROJ_NAME}
@@ -197,10 +247,6 @@
                     the Apple developer tools. The default system paths were searched in addition to ${OSX_DEVELOPER_ROOT}/usr/bin")
 endif()
 
-# Make sure the 'Resources' Directory is correctly created before we build
-ADD_CUSTOM_COMMAND(TARGET ${PROJ_NAME} PRE_BUILD
-                      COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${PROJ_NAME}.app/Contents/Resources)
-
 # Compile the .xib files using the 'ibtool' program with the destination being the app package
 FOREACH(xib ${ringclient_XIBS})
   ADD_CUSTOM_COMMAND(TARGET ${PROJ_NAME} POST_BUILD
@@ -211,7 +257,7 @@
 
 ENDFOREACH()
 
-set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} ${CMAKE_INSTALL_PREFIX})
+SET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} ${CMAKE_INSTALL_PREFIX})
 
 SET(APPS "\${CMAKE_INSTALL_PREFIX}/${PROJ_NAME}.app")
 
@@ -249,7 +295,7 @@
 ENDFOREACH()
 
 # directories to look for dependencies
-SET(DIRS ${CMAKE_INSTALL_PREFIX}/lib ${QT_LIB_DIR})
+SET(DIRS ${CMAKE_INSTALL_PREFIX}/lib ${QT_LIB_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/sparkle)
 
 INSTALL(CODE "
     file(GLOB_RECURSE QTPLUGINS
diff --git a/README.md b/README.md
index b2eaadd..e5567c7 100644
--- a/README.md
+++ b/README.md
@@ -14,21 +14,47 @@
 Build instructions
 ==================
 
-2. mkdir build && cd build
+Build Sparkle framework (optional)
+----------------------------------
+Ring can ship with the Sparkle framework to allow automatic app updates.
+This can be disabled for your custom build by specifying -DENABLE_SPARKLE=false
+in the cmake phase.
 
-3. export CMAKE_PREFIX_PATH=<dir_to_qt5>
+1. cd sparkle/
+2. git submodule update
+3. cd Sparkle/
+4. make release
+5. A Finder window will popup in the directory where Sparkle has been built.
+Copy-paste the Sparkle.framework in sparkle/ in our project, or in
+/Library/Frameworks on your system.
+
+Build Client
+------------
+
+1. mkdir build && cd build
+
+2. export CMAKE_PREFIX_PATH=<dir_to_qt5>
 
 Now generate an Xcode project with CMake:
-4. cmake ../ -DCMAKE_INSTALL_PREFIX=<libringclient_install_path> -G Xcode
-5. open Ring.xcodeproj/
-6. Build and run it from Xcode. You can also generate the final Ring.app bundle.
+3. cmake ../ -DCMAKE_INSTALL_PREFIX=<libringclient_install_path> -G Xcode
+4. open Ring.xcodeproj/
+5. Build and run it from Xcode. You can also generate the final Ring.app bundle.
 
 You can also build it from the command line:
 
-4. cmake ../ -DCMAKE_INSTALL_PREFIX=<libringclient_install_path>
-5. make
-6. open Ring.app/
+3. cmake ../ -DCMAKE_INSTALL_PREFIX=<libringclient_install_path>
+4. make
+5. open Ring.app/
 
+If you want to create the final app (self-containing .dmg):
+
+4. make install
+5. cpack -G DragNDrop Ring
+
+Notes:
+
+By default the client version is specified in CMakeLists.txt but it can be
+overriden by specifying -DRING_VERSION=<num> in the cmake command line.
 
 Debugging
 ==================
diff --git a/cmake/MacOSXBundleInfo.plist.in b/cmake/MacOSXBundleInfo.plist.in
index 857c6f6..379e709 100644
--- a/cmake/MacOSXBundleInfo.plist.in
+++ b/cmake/MacOSXBundleInfo.plist.in
@@ -2,36 +2,40 @@
 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>English</string>
-	<key>CFBundleExecutable</key>
-	<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
-	<key>CFBundleGetInfoString</key>
-	<string>${MACOSX_BUNDLE_INFO_STRING}</string>
-	<key>CFBundleIconFile</key>
-	<string>${MACOSX_BUNDLE_ICON_FILE}</string>
-	<key>CFBundleIdentifier</key>
-	<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleLongVersionString</key>
-	<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
-	<key>CFBundleName</key>
-	<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
-	<key>CSResourcesFileMapped</key>
-	<true/>
-	<key>LSRequiresCarbon</key>
-	<true/>
-	<key>NSHumanReadableCopyright</key>
-	<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+    <key>CFBundleDevelopmentRegion</key>
+    <string>English</string>
+    <key>CFBundleExecutable</key>
+    <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+    <key>CFBundleGetInfoString</key>
+    <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+    <key>CFBundleIconFile</key>
+    <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+    <key>CFBundleIdentifier</key>
+    <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+    <key>SUPublicDSAKeyFile</key>
+    <string>dsa_pub.pem</string>
+    <key>SUFeedURL</key>
+    <string>http://gpl.savoirfairelinux.net/ring-download/mac_osx/sparkle-ring.xml</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleLongVersionString</key>
+    <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+    <key>CFBundleName</key>
+    <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleShortVersionString</key>
+    <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleVersion</key>
+    <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+    <key>CSResourcesFileMapped</key>
+    <true/>
+    <key>LSRequiresCarbon</key>
+    <true/>
+    <key>NSHumanReadableCopyright</key>
+    <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
     <key>NSHighResolutionCapable</key>
     <string>True</string>
     <key>NSMainNibFile</key>
diff --git a/sparkle/LICENSE b/sparkle/LICENSE
new file mode 100644
index 0000000..f4020f8
--- /dev/null
+++ b/sparkle/LICENSE
@@ -0,0 +1,60 @@
+Copyright (c) 2006-2013 Andy Matuschak.
+Copyright (c) 2009-2013 Elgato Systems GmbH.
+Copyright (c) 2011-2014 Kornel LesiƄski.
+Copyright (c) 2014 C.W. Betts.
+Copyright (c) 2014 Petroules Corporation.
+Copyright (c) 2014 Big Nerd Ranch.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+=================
+EXTERNAL LICENSES
+=================
+
+bspatch.c and bsdiff.c, from bsdiff 4.3 <http://www.daemonology.net/bsdiff/>:
+    Copyright (c) 2003-2005 Colin Percival.
+
+sais.c and sais.c, from sais-lite (2010/08/07) <https://sites.google.com/site/yuta256/sais>:
+    Copyright (c) 2008-2010 Yuta Mori.
+
+SUDSAVerifier.m:
+    Copyright (c) 2011 Mark Hamlin.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted providing that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/sparkle/Sparkle b/sparkle/Sparkle
new file mode 160000
index 0000000..d0cc3b6
--- /dev/null
+++ b/sparkle/Sparkle
@@ -0,0 +1 @@
+Subproject commit d0cc3b63b4da6b952fa7b96607cd80fb75a9b48f
diff --git a/sparkle/dsa_pub.pem b/sparkle/dsa_pub.pem
new file mode 100644
index 0000000..97455e2
--- /dev/null
+++ b/sparkle/dsa_pub.pem
@@ -0,0 +1,36 @@
+-----BEGIN PUBLIC KEY-----
+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
+ZnO5P9x/rPIJLCXY4xQYBryQCMu6JC5ibWzP
+-----END PUBLIC KEY-----
diff --git a/sparkle/sign_update.sh b/sparkle/sign_update.sh
new file mode 100644
index 0000000..d15c3cd
--- /dev/null
+++ b/sparkle/sign_update.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+set -o pipefail
+if [ "$#" -ne 2 ]; then
+  echo "Usage: $0 update_archive private_key"
+  exit 1
+fi
+openssl=/usr/bin/openssl
+$openssl dgst -sha1 -binary < "$1" | $openssl dgst -dss1 -sign "$2" | base64 --wrap=0
+
diff --git a/sparkle/sparkle-xml-updater.sh b/sparkle/sparkle-xml-updater.sh
new file mode 100644
index 0000000..d0dc91b
--- /dev/null
+++ b/sparkle/sparkle-xml-updater.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# Take the package to add as argument ./sparkle-xml-updater.sh ring.dmg
+
+REPO_FOLDER=<dir>
+SPARKLE_FILE=<xml_filename>
+REPO_URL=<url>
+PACKAGE=$1
+DSA_KEY=<path_to_key_file>
+
+if [ ! -f ${PACKAGE} -o ! -f ${DSA_KEY} ]; then
+    echo "Can't find package or dsa key, aborting..."
+    exit 1
+fi
+
+if [ -f ${REPO_FOLDER}/${SPARKLE_FILE} ]; then
+    ITEMS=$(sed -n "/<item>/,/<\/item>/p" ${REPO_FOLDER}/${SPARKLE_FILE}) 
+fi
+
+cat << EOFILE > ${REPO_FOLDER}/${SPARKLE_FILE}
+<?xml version="1.0" encoding="utf-8"?>
+<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <channel>
+        <title>Ring - nightly</title>
+        <link>${REPO_URL}/${SPARKLE_FILE}</link>
+        <description>Most recent changes with links to updates.</description>
+        <language>en</language>
+        <item>
+            <title>Ring nightly $(date "+%Y/%m/%d %H:%M")</title>
+            <pubDate>$(date -R)</pubDate>
+            <enclosure url="${REPO_URL}/$(basename ${PACKAGE})" sparkle:version="$(date +%Y%m%d%H%M)" sparkle:shortVersionString="nightly-$(date "+%Y%m%d")" length="$(stat -c %s ${PACKAGE})" type="application/octet-stream" sparkle:dsaSignature="$(/opt/joulupukki/mac_keys/sign_update.sh ${PACKAGE} ${DSA_KEY})" />
+            <sparkle:minimumSystemVersion>10.7</sparkle:minimumSystemVersion>
+        </item>
+$(echo -e "${ITEMS}")
+    </channel>
+</rss>
+EOFILE
+
diff --git a/src/AppDelegate.mm b/src/AppDelegate.mm
index 197b320..6325438 100644
--- a/src/AppDelegate.mm
+++ b/src/AppDelegate.mm
@@ -36,10 +36,18 @@
 #import <QItemSelectionModel>
 #import <account.h>
 
+#if ENABLE_SPARKLE
+#import <Sparkle/Sparkle.h>
+#endif
+
 #import "Constants.h"
 #import "RingWizardWC.h"
 
+#if ENABLE_SPARKLE
+@interface AppDelegate() <SUUpdaterDelegate>
+#else
 @interface AppDelegate()
+#endif
 
 @property RingWindowController* ringWindowController;
 @property RingWizardWC* wizard;
@@ -51,7 +59,6 @@
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
     [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"];
 
-
     [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
 
     NSAppleEventManager* appleEventManager = [NSAppleEventManager sharedAppleEventManager];
@@ -148,4 +155,30 @@
     [[NSApplication sharedApplication] terminate:self];
 }
 
+#if ENABLE_SPARKLE
+
+#pragma mark -
+#pragma mark Sparkle delegate
+
+- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update
+{
+    [NSApp activateIgnoringOtherApps:YES];
+}
+
+- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)bundle
+{
+    return YES;
+}
+
+- (BOOL)updaterShouldRelaunchApplication:(SUUpdater *)updater
+{
+    return YES;
+}
+
+- (void)updater:(SUUpdater *)updater didAbortWithError:(NSError *)error
+{
+    NSLog(@"Error:%@", error.localizedDescription);
+}
+
+#endif
 @end
diff --git a/src/GeneralPrefsVC.mm b/src/GeneralPrefsVC.mm
index 866972b..a9f88e6 100644
--- a/src/GeneralPrefsVC.mm
+++ b/src/GeneralPrefsVC.mm
@@ -31,12 +31,19 @@
 
 #import <categorizedhistorymodel.h>
 
+#if ENABLE_SPARKLE
+#import <Sparkle/Sparkle.h>
+#endif
+
 #import "Constants.h"
 
 @interface GeneralPrefsVC ()
 @property (unsafe_unretained) IBOutlet NSTextField *historyChangedLabel;
 @property (unsafe_unretained) IBOutlet NSView *advancedGeneralSettings;
 @property (unsafe_unretained) IBOutlet NSButton *startUpButton;
+@property (unsafe_unretained) IBOutlet NSButton *toggleAutomaticUpdateCheck;
+@property (unsafe_unretained) IBOutlet NSPopUpButton *checkIntervalPopUp;
+@property (unsafe_unretained) IBOutlet NSView *sparkleContainer;
 
 @end
 
@@ -44,6 +51,9 @@
 @synthesize historyChangedLabel;
 @synthesize advancedGeneralSettings;
 @synthesize startUpButton;
+@synthesize toggleAutomaticUpdateCheck;
+@synthesize checkIntervalPopUp;
+@synthesize sparkleContainer;
 
 - (void)loadView
 {
@@ -53,6 +63,17 @@
 
     [startUpButton setState:[self isLaunchAtStartup]];
 
+#if ENABLE_SPARKLE
+    [sparkleContainer setHidden:NO];
+    SUUpdater *updater = [SUUpdater sharedUpdater];
+    [toggleAutomaticUpdateCheck bind:@"value" toObject:updater withKeyPath:@"automaticallyChecksForUpdates" options:nil];
+
+    [checkIntervalPopUp bind:@"enabled" toObject:updater withKeyPath:@"automaticallyChecksForUpdates" options:nil];
+    [checkIntervalPopUp bind:@"selectedTag" toObject:updater withKeyPath:@"updateCheckInterval" options:nil];
+#else
+    [sparkleContainer setHidden:YES];
+#endif
+
     //[advancedGeneralSettings setHidden:![[NSUserDefaults standardUserDefaults] boolForKey:Preferences::ShowAdvanced]];
 }
 
diff --git a/ui/GeneralPrefs.xib b/ui/GeneralPrefs.xib
index 9bdead4..3167824 100644
--- a/ui/GeneralPrefs.xib
+++ b/ui/GeneralPrefs.xib
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14D2134" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
     <dependencies>
         <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="7706"/>
     </dependencies>
@@ -7,8 +7,11 @@
         <customObject id="-2" userLabel="File's Owner" customClass="GeneralPrefsVC">
             <connections>
                 <outlet property="advancedGeneralSettings" destination="VH6-yw-pgr" id="lSD-RY-Puf"/>
+                <outlet property="checkIntervalPopUp" destination="RYP-3d-PCa" id="JNO-GR-CV8"/>
                 <outlet property="historyChangedLabel" destination="Gyi-ID-Z3v" id="aoO-Fh-UCQ"/>
+                <outlet property="sparkleContainer" destination="yVO-jk-ay3" id="zni-hI-88D"/>
                 <outlet property="startUpButton" destination="1Nr-L4-fcd" id="veu-Hi-c7L"/>
+                <outlet property="toggleAutomaticUpdateCheck" destination="MCd-PD-kd7" id="rSB-ac-Nm2"/>
                 <outlet property="view" destination="c22-O7-iKe" id="kqH-6G-Ohq"/>
             </connections>
         </customObject>
@@ -132,7 +135,7 @@
                     </connections>
                 </button>
                 <customView hidden="YES" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VH6-yw-pgr">
-                    <rect key="frame" x="20" y="171" width="859" height="181"/>
+                    <rect key="frame" x="20" y="69" width="859" height="181"/>
                     <subviews>
                         <button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kAy-G5-0gJ">
                             <rect key="frame" x="65" y="116" width="104" height="18"/>
@@ -290,9 +293,45 @@
                         </button>
                     </subviews>
                 </customView>
+                <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yVO-jk-ay3">
+                    <rect key="frame" x="20" y="270" width="506" height="82"/>
+                    <subviews>
+                        <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="diX-uH-Ce8">
+                            <rect key="frame" x="14" y="45" width="52" height="17"/>
+                            <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Update" id="r4u-t3-gBc">
+                                <font key="font" metaFont="systemBold"/>
+                                <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                            </textFieldCell>
+                        </textField>
+                        <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RYP-3d-PCa" userLabel="Update interval">
+                            <rect key="frame" x="265" y="17" width="100" height="26"/>
+                            <popUpButtonCell key="cell" type="push" title="Monthly" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="2629800" imageScaling="proportionallyDown" inset="2" selectedItem="42E-UY-qlP" id="tTF-gp-Rti">
+                                <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
+                                <font key="font" metaFont="menu"/>
+                                <menu key="menu" id="GJ4-0X-PTn">
+                                    <items>
+                                        <menuItem title="Hourly" tag="3600" id="mbu-TH-bs8"/>
+                                        <menuItem title="Daily" tag="86400" id="cB6-4m-9MU"/>
+                                        <menuItem title="Weekly" tag="604800" id="AId-am-73Q"/>
+                                        <menuItem title="Monthly" state="on" tag="2629800" id="42E-UY-qlP"/>
+                                    </items>
+                                </menu>
+                            </popUpButtonCell>
+                        </popUpButton>
+                        <button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MCd-PD-kd7">
+                            <rect key="frame" x="31" y="21" width="221" height="18"/>
+                            <buttonCell key="cell" type="check" title="Automatically check for updates" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="T3a-yx-ZaW">
+                                <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+                                <font key="font" metaFont="system"/>
+                            </buttonCell>
+                        </button>
+                    </subviews>
+                </customView>
             </subviews>
             <point key="canvasLocation" x="523.5" y="220.5"/>
         </customView>
         <userDefaultsController representsSharedInstance="YES" id="Sz0-vm-i3t"/>
+        <customObject id="VEJ-ic-3Ub" customClass="SUUpdater"/>
     </objects>
 </document>
diff --git a/ui/MainMenu.xib b/ui/MainMenu.xib
index a7263c7..5c46bfe 100644
--- a/ui/MainMenu.xib
+++ b/ui/MainMenu.xib
@@ -2,13 +2,13 @@
 <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
 	<data>
 		<int key="IBDocument.SystemTarget">101000</int>
-		<string key="IBDocument.SystemVersion">13F34</string>
-		<string key="IBDocument.InterfaceBuilderVersion">6254</string>
-		<string key="IBDocument.AppKitVersion">1265.21</string>
-		<string key="IBDocument.HIToolboxVersion">698.00</string>
+		<string key="IBDocument.SystemVersion">14D2134</string>
+		<string key="IBDocument.InterfaceBuilderVersion">7706</string>
+		<string key="IBDocument.AppKitVersion">1347.57</string>
+		<string key="IBDocument.HIToolboxVersion">758.70</string>
 		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
 			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
-			<string key="NS.object.0">6254</string>
+			<string key="NS.object.0">7706</string>
 		</object>
 		<array key="IBDocument.IntegratedClassDependencies">
 			<string>NSCustomObject</string>
@@ -70,6 +70,14 @@
 									<reference key="NSOnImage" ref="35465992"/>
 									<reference key="NSMixedImage" ref="502551668"/>
 								</object>
+								<object class="NSMenuItem" id="709467494">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">Check for Update...</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
 								<object class="NSMenuItem" id="304266470">
 									<reference key="NSMenu" ref="110575045"/>
 									<bool key="NSIsDisabled">YES</bool>
@@ -710,6 +718,9 @@
 			<object class="NSCustomObject" id="755631768">
 				<string key="NSClassName">NSFontManager</string>
 			</object>
+			<object class="NSCustomObject" id="931776921">
+				<string key="NSClassName">SUUpdater</string>
+			</object>
 		</array>
 		<object class="IBObjectContainer" key="IBDocument.Objects">
 			<array key="connectionRecords">
@@ -1065,6 +1076,14 @@
 					</object>
 					<int key="connectionID">591</int>
 				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">checkForUpdates:</string>
+						<reference key="source" ref="931776921"/>
+						<reference key="destination" ref="709467494"/>
+					</object>
+					<int key="connectionID">595</int>
+				</object>
 			</array>
 			<object class="IBMutableOrderedSet" key="objectRecords">
 				<array key="orderedObjects">
@@ -1293,6 +1312,7 @@
 							<reference ref="238522557"/>
 							<reference ref="342932134"/>
 							<reference ref="478989275"/>
+							<reference ref="709467494"/>
 						</array>
 						<reference key="parent" ref="694149608"/>
 					</object>
@@ -1595,6 +1615,16 @@
 						<reference key="object" ref="478989275"/>
 						<reference key="parent" ref="110575045"/>
 					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">592</int>
+						<reference key="object" ref="931776921"/>
+						<reference key="parent" ref="0"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">593</int>
+						<reference key="object" ref="709467494"/>
+						<reference key="parent" ref="110575045"/>
+					</object>
 				</array>
 			</object>
 			<dictionary class="NSMutableDictionary" key="flattenedProperties">
@@ -1677,103 +1707,17 @@
 				<string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
 				<string key="58.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
 				<string key="589.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+				<string key="592.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+				<string key="593.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
 				<string key="92.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
 			</dictionary>
 			<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
 			<nil key="activeLocalization"/>
 			<dictionary class="NSMutableDictionary" key="localizations"/>
 			<nil key="sourceID"/>
-			<int key="maxID">591</int>
+			<int key="maxID">595</int>
 		</object>
-		<object class="IBClassDescriber" key="IBDocument.Classes">
-			<array class="NSMutableArray" key="referencedPartialClassDescriptions">
-				<object class="IBPartialClassDescription">
-					<string key="className">AppDelegate</string>
-					<string key="superclassName">NSObject</string>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">../../AppDelegate.h</string>
-					</object>
-				</object>
-				<object class="IBPartialClassDescription">
-					<string key="className">AppDelegate</string>
-					<object class="NSMutableDictionary" key="actions">
-						<string key="NS.key.0">showWizard:</string>
-						<string key="NS.object.0">id</string>
-					</object>
-					<object class="NSMutableDictionary" key="actionInfosByName">
-						<string key="NS.key.0">showWizard:</string>
-						<object class="IBActionInfo" key="NS.object.0">
-							<string key="name">showWizard:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-					</object>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">../../AppDelegate.mm</string>
-					</object>
-				</object>
-				<object class="IBPartialClassDescription">
-					<string key="className">RingWindowController</string>
-					<string key="superclassName">NSWindowController</string>
-					<dictionary class="NSMutableDictionary" key="actions">
-						<string key="closePreferences:">NSToolbarItem</string>
-						<string key="openPreferences:">id</string>
-					</dictionary>
-					<dictionary class="NSMutableDictionary" key="actionInfosByName">
-						<object class="IBActionInfo" key="closePreferences:">
-							<string key="name">closePreferences:</string>
-							<string key="candidateClassName">NSToolbarItem</string>
-						</object>
-						<object class="IBActionInfo" key="openPreferences:">
-							<string key="name">openPreferences:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-					</dictionary>
-					<object class="NSMutableDictionary" key="outlets">
-						<string key="NS.key.0">currentView</string>
-						<string key="NS.object.0">NSView</string>
-					</object>
-					<object class="NSMutableDictionary" key="toOneOutletInfosByName">
-						<string key="NS.key.0">currentView</string>
-						<object class="IBToOneOutletInfo" key="NS.object.0">
-							<string key="name">currentView</string>
-							<string key="candidateClassName">NSView</string>
-						</object>
-					</object>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">../../RingWindowController.h</string>
-					</object>
-				</object>
-				<object class="IBPartialClassDescription">
-					<string key="className">RingWindowController</string>
-					<dictionary class="NSMutableDictionary" key="actions">
-						<string key="closePreferences:">NSToolbarItem</string>
-						<string key="openPreferences:">id</string>
-						<string key="placeCall:">id</string>
-					</dictionary>
-					<dictionary class="NSMutableDictionary" key="actionInfosByName">
-						<object class="IBActionInfo" key="closePreferences:">
-							<string key="name">closePreferences:</string>
-							<string key="candidateClassName">NSToolbarItem</string>
-						</object>
-						<object class="IBActionInfo" key="openPreferences:">
-							<string key="name">openPreferences:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-						<object class="IBActionInfo" key="placeCall:">
-							<string key="name">placeCall:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-					</dictionary>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">../../RingWindowController.mm</string>
-					</object>
-				</object>
-			</array>
-		</object>
+		<object class="IBClassDescriber" key="IBDocument.Classes"/>
 		<int key="IBDocument.localizationMode">0</int>
 		<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
 		<bool key="IBDocument.previouslyAttemptedUpgradeToXcode5">NO</bool>
@@ -1784,8 +1728,8 @@
 		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
 		<int key="IBDocument.defaultPropertyAccessControl">3</int>
 		<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
-			<string key="NSMenuCheckmark">{11, 11}</string>
-			<string key="NSMenuMixedState">{10, 3}</string>
+			<string key="NSMenuCheckmark">{12, 12}</string>
+			<string key="NSMenuMixedState">{10, 2}</string>
 		</dictionary>
 		<bool key="IBDocument.UseAutolayout">YES</bool>
 	</data>