Enable building of ChronoShare.app

Temporarily disable integrated tests

Change-Id: I652e27f1a19dc9f5b3e0b1399e0fe015f61b3e81
diff --git a/.jenkins.d/10-build.sh b/.jenkins.d/10-build.sh
index db41533..9653d1c 100755
--- a/.jenkins.d/10-build.sh
+++ b/.jenkins.d/10-build.sh
@@ -39,6 +39,3 @@
 ./waf -j1 --color=yes build
 
 # (tests will be run against debug version)
-
-# Install
-sudo ./waf -j1 --color=yes install
diff --git a/.waf-tools/cryptopp.py b/.waf-tools/cryptopp.py
deleted file mode 100644
index 1632ab6..0000000
--- a/.waf-tools/cryptopp.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#! /usr/bin/env python
-# encoding: utf-8
-
-'''
-
-When using this tool, the wscript will look like:
-
-    def options(opt):
-        opt.load('compiler_cxx cryptopp')
-
-    def configure(conf):
-        conf.load('compiler_cxx cryptopp')
-        conf.check_cryptopp()
-
-    def build(bld):
-        bld(source='main.cpp', target='app', use='CRYPTOPP')
-
-Options are generated, in order to specify the location of cryptopp includes/libraries.
-
-
-'''
-import sys
-import re
-from waflib import Utils,Logs,Errors
-from waflib.Configure import conf
-CRYPTOPP_DIR = ['/usr', '/usr/local', '/opt/local', '/sw']
-CRYPTOPP_VERSION_FILE = 'config.h'
-
-CRYPTOPP_CHECK_FRAGMENT = '''
-#include "../../src/security/v1/cryptopp.hpp"
-#include <iostream>
-
-int
-main()
-{
-  using namespace CryptoPP;
-
-  std::string buffer = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
-  SHA256 hash;
-  StringSource(buffer, true, new HashFilter(hash, new FileSink(std::cout)));
-  StringSource(reinterpret_cast<const uint8_t*>(buffer.c_str()), buffer.size(),
-               true, new HashFilter(hash, new FileSink(std::cout)));
-}
-'''
-
-def options(opt):
-    opt.add_option('--with-cryptopp', type='string', default=None, dest='cryptopp_dir',
-                   help='''Path to where CryptoPP is installed, e.g., /usr/local''')
-
-@conf
-def __cryptopp_get_version_file(self, dir):
-    try:
-        return self.root.find_dir(dir).find_node('%s/%s' % ('include/cryptopp',
-                                                            CRYPTOPP_VERSION_FILE))
-    except:
-        return None
-
-@conf
-def __cryptopp_find_root_and_version_file(self, *k, **kw):
-    root = k and k[0] or kw.get('path', self.options.cryptopp_dir)
-
-    file = self.__cryptopp_get_version_file(root)
-    if root and file:
-        return (root, file)
-    for dir in CRYPTOPP_DIR:
-        file = self.__cryptopp_get_version_file(dir)
-        if file:
-            return (dir, file)
-
-    if root:
-        self.fatal('CryptoPP not found in %s' % root)
-    else:
-        self.fatal('CryptoPP not found, please provide a --with-cryptopp=PATH argument (see help)')
-
-@conf
-def check_cryptopp(self, *k, **kw):
-    if not self.env['CXX']:
-        self.fatal('Load a c++ compiler first, e.g., conf.load("compiler_cxx")')
-
-    var = kw.get('uselib_store', 'CRYPTOPP')
-    mandatory = kw.get('mandatory', True)
-
-    use = kw.get('use', 'PTHREAD')
-
-    self.start_msg('Checking Crypto++ lib')
-    (root, file) = self.__cryptopp_find_root_and_version_file(*k, **kw)
-
-    try:
-        txt = file.read()
-        re_version = re.compile('^#define\\s+CRYPTOPP_VERSION\\s+([0-9]+)', re.M)
-        match = re_version.search(txt)
-
-        if match:
-            self.env.CRYPTOPP_VERSION = match.group(1)
-            v = int(self.env.CRYPTOPP_VERSION)
-            (major, minor, patch) = (int(v / 100), int(v % 100 / 10), int(v % 10))
-            self.end_msg("%d.%d.%d" % (major, minor, patch))
-        else:
-            self.fatal('CryptoPP files are present, but are not recognizable')
-    except:
-        self.fatal('CryptoPP not found or is not usable')
-
-    isLibWorking = False
-    for defines in [[], ['CRYPTOPP_DISABLE_ASM']]:
-        try:
-            self.check_cxx(msg='Checking if CryptoPP library works',
-                           fragment=CRYPTOPP_CHECK_FRAGMENT,
-                           lib='cryptopp',
-                           includes="%s/include" % root,
-                           libpath="%s/lib" % root,
-                           mandatory=True,
-                           use=use,
-                           defines=defines,
-                           uselib_store=var)
-            isLibWorking = True
-            break
-        except:
-            # try another flags
-            pass
-
-    if mandatory and not isLibWorking:
-        self.fatal('CryptoPP is present, but is not usable')
diff --git a/.waf-tools/osx-frameworks.py b/.waf-tools/osx-frameworks.py
index 7830f8f..9936778 100644
--- a/.waf-tools/osx-frameworks.py
+++ b/.waf-tools/osx-frameworks.py
@@ -5,16 +5,14 @@
 from waflib.Configure import conf
 
 OSX_SECURITY_CODE='''
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-#include <Security/SecRandom.h>
-#include <CoreServices/CoreServices.h>
-#include <Security/SecDigestTransform.h>
-
-int main(int argc, char **argv) {
-    (void)argc; (void)argv;
-    return 0;
-}
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#import <Sparkle/Sparkle.h>
+#import <CoreWLAN/CWInterface.h>
+#import <CoreWLAN/CoreWLAN.h>
+#import <CoreWLAN/CoreWLANConstants.h>
+#import <CoreWLAN/CoreWLANTypes.h>
+int main() { }
 '''
 
 @conf
@@ -25,46 +23,46 @@
         conf.check_cxx(framework_name='CoreWLAN',   uselib_store='OSX_COREWLAN',   define_name='HAVE_COREWLAN',
                        use="OSX_FOUNDATION", mandatory=False, compile_filename='test.mm')
 
-        if conf.options.autoupdate:
-            def check_sparkle(**kwargs):
-              conf.check_cxx (framework_name="Sparkle", header_name=["Foundation/Foundation.h", "AppKit/AppKit.h"],
-                              uselib_store='OSX_SPARKLE', define_name='HAVE_SPARKLE', mandatory=True,
-                              compile_filename='test.mm', use="OSX_FOUNDATION OSX_APPKIT",
-                              **kwargs
-                              )
+        def check_sparkle(**kwargs):
+          conf.check_cxx(framework_name="Sparkle", header_name=["Foundation/Foundation.h", "AppKit/AppKit.h"],
+                         uselib_store='OSX_SPARKLE', define_name='HAVE_SPARKLE', mandatory=True,
+                         compile_filename='test.mm', use="OSX_FOUNDATION OSX_APPKIT",
+                         **kwargs
+                         )
+        try:
+            # Try standard paths first
+            check_sparkle()
+        except:
             try:
-                # Try standard paths first
-                check_sparkle()
+                # Try local path
+                Logs.info ("Check local version of Sparkle framework")
+                check_sparkle(cxxflags="-F%s/osx/Frameworks/" % conf.path.abspath(),
+                              linkflags="-F%s/osx/Frameworks/" % conf.path.abspath())
+                conf.env.HAVE_LOCAL_SPARKLE = 1
             except:
-                try:
-                    # Try local path
-                    Logs.info ("Check local version of Sparkle framework")
-                    check_sparkle(cxxflags="-F%s/osx/Frameworks/" % conf.path.abspath(),
-                                  linkflags="-F%s/osx/Frameworks/" % conf.path.abspath())
-                    conf.env.HAVE_LOCAL_SPARKLE = 1
-                except:
-                    import urllib, subprocess, os, shutil
-                    if not os.path.exists('osx/Frameworks/Sparkle.framework'):
-                        # Download to local path and retry
-                        Logs.info ("Sparkle framework not found, trying to download it to 'build/'")
+                import urllib, subprocess, os, shutil
+                if not os.path.exists('osx/Frameworks/Sparkle.framework'):
+                    # Download to local path and retry
+                    Logs.info ("Sparkle framework not found, trying to download it to 'build/'")
 
-                        urllib.urlretrieve ("http://sparkle.andymatuschak.org/files/Sparkle%201.5b6.zip", "build/Sparkle.zip")
-                        if os.path.exists('build/Sparkle.zip'):
-                            try:
-                                subprocess.check_call (['unzip', '-qq', 'build/Sparkle.zip', '-d', 'build/Sparkle'])
-                                os.remove ("build/Sparkle.zip")
-                                if not os.path.exists("osx/Frameworks"):
-                                    os.mkdir ("osx/Frameworks")
-                                os.rename ("build/Sparkle/Sparkle.framework", "osx/Frameworks/Sparkle.framework")
-                                shutil.rmtree("build/Sparkle", ignore_errors=True)
+                    urllib.urlretrieve ("https://github.com/sparkle-project/Sparkle/releases/download/1.16.0/Sparkle-1.16.0.tar.bz2", "build/Sparkle.tar.bz2")
+                    if os.path.exists('build/Sparkle.tar.bz2'):
+                        try:
+                            subprocess.check_call(['mkdir', 'build/Sparkle'])
+                            subprocess.check_call(['tar', 'xjf', 'build/Sparkle.tar.bz2', '-C', 'build/Sparkle'])
+                            os.remove("build/Sparkle.tar.bz2")
+                            if not os.path.exists("osx/Frameworks"):
+                                os.mkdir ("osx/Frameworks")
+                            os.rename("build/Sparkle/Sparkle.framework", "osx/Frameworks/Sparkle.framework")
 
-                                check_sparkle(cxxflags="-F%s/osx/Frameworks/" % conf.path.abspath(),
-                                              linkflags="-F%s/osx/Frameworks/" % conf.path.abspath())
-                                conf.env.HAVE_LOCAL_SPARKLE = 1
-                            except subprocess.CalledProcessError as e:
-                                conf.fatal("Cannot find Sparkle framework. Auto download failed: '%s' returned %s" % (' '.join(e.cmd), e.returncode))
-                            except:
-                                conf.fatal("Unknown Error happened when auto downloading Sparkle framework")
+                            check_sparkle(cxxflags="-F%s/osx/Frameworks/" % conf.path.abspath(),
+                                          linkflags="-F%s/osx/Frameworks/" % conf.path.abspath())
+                            conf.env.HAVE_LOCAL_SPARKLE = 1
+                        except subprocess.CalledProcessError as e:
+                            conf.fatal("Cannot find Sparkle framework. Auto download failed: '%s' returned %s" % (' '.join(e.cmd), e.returncode))
+                        except:
+                            conf.fatal("Unknown Error happened when auto downloading Sparkle framework")
 
-            if conf.is_defined('HAVE_SPARKLE'):
-                conf.env.HAVE_SPARKLE = 1 # small cheat for wscript
+        conf.env['LDFLAGS_OSX_SPARKLE'] += ['-Wl,-rpath,@loader_path/../Frameworks']
+        if conf.is_defined('HAVE_SPARKLE'):
+            conf.env.HAVE_SPARKLE = 1 # small cheat for wscript
diff --git a/gui/chronosharegui.cpp b/gui/chronosharegui.cpp
index 687d14c..3159699 100644
--- a/gui/chronosharegui.cpp
+++ b/gui/chronosharegui.cpp
@@ -49,9 +49,8 @@
 ChronoShareGui::ChronoShareGui(QWidget* parent)
   : QDialog(parent)
   , m_httpServer(0)
-#ifdef SPARKLE_SUPPORTED
-  , m_autoUpdate(
-      new SparkleAutoUpdate(tr("http://irl.cs.ucla.edu/~zhenkai/chronoshare_dist/chronoshare.xml")))
+#ifdef AUTOUPDATE
+  , m_sparkle(CHRONOSHARE_APPCAST)
 #endif
 {
   setWindowTitle("Settings");
@@ -128,6 +127,9 @@
   , m_dirPath(dirPath)
   , m_username(username)
   , m_sharedFolderName(sharedFolderName)
+#ifdef AUTOUPDATE
+  , m_sparkle(CHRONOSHARE_APPCAST)
+#endif
 {
   if (m_username.isNull() || m_username == "" || m_sharedFolderName.isNull() ||
       m_sharedFolderName == "" || m_dirPath.isNull() || m_dirPath == "") {
@@ -243,10 +245,7 @@
   // cleanup
   delete m_trayIcon;
   delete m_trayIconMenu;
-#ifdef SPARKLE_SUPPORTED
-  delete m_autoUpdate;
-  delete m_checkForUpdates;
-#endif
+
   delete m_openFolder;
   delete m_viewSettings;
   delete m_changeFolder;
@@ -259,9 +258,6 @@
   delete button;
   delete label;
   delete mainLayout;
-
-  // to avoid `private field 'm_checkForUpdates' is not used` warning/error
-  (void)(m_checkForUpdates);
 }
 
 void
@@ -332,10 +328,10 @@
   m_changeFolder = new QAction(tr("&Change Folder"), this);
   connect(m_changeFolder, SIGNAL(triggered()), this, SLOT(openFileDialog()));
 
-#ifdef SPARKLE_SUPPORTED
-  m_checkForUpdates = new QAction(tr("Check For Updates"), this);
-  connect(m_checkForUpdates, SIGNAL(triggered()), this, SLOT(onCheckForUpdates()));
-#endif
+#ifdef AUTOUPDATE
+  m_checkForUpdates = new QAction("Check for updates", this);
+  connect(m_checkForUpdates, SIGNAL(triggered()), this, SLOT(checkForUpdates()));
+#endif // AUTOUPDATE
 
   // create the "quit program" action
   m_quitProgram = new QAction(tr("&Quit"), this);
@@ -356,10 +352,10 @@
   m_trayIconMenu->addAction(m_viewSettings);
   m_trayIconMenu->addAction(m_changeFolder);
 
-#ifdef SPARKLE_SUPPORTED
+#ifdef AUTOUPDATE
   m_trayIconMenu->addSeparator();
   m_trayIconMenu->addAction(m_checkForUpdates);
-#endif
+#endif // AUTOUPDATE
 
   m_trayIconMenu->addSeparator();
   m_trayIconMenu->addAction(m_quitProgram);
@@ -376,16 +372,6 @@
 }
 
 void
-ChronoShareGui::onCheckForUpdates()
-{
-#ifdef SPARKLE_SUPPORTED
-  cout << "+++++++++++ trying to update +++++++ " << endl;
-  m_autoUpdate->checkForUpdates();
-  cout << "+++++++++++ end trying to update +++++++ " << endl;
-#endif
-}
-
-void
 ChronoShareGui::setIcon()
 {
   // set the icon image
@@ -598,7 +584,9 @@
 
   // Load Settings
   // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
-  QSettings settings(QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
+  QSettings settings;
+
+  _LOG_DEBUG("load settings");
 
   if (settings.contains("username")) {
     m_username = settings.value("username", "admin").toString();
@@ -637,7 +625,7 @@
 {
   // Save Settings
   // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
-  QSettings settings(QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
+  QSettings settings;
 
   settings.setValue("dirPath", m_dirPath);
   settings.setValue("username", m_username);
@@ -660,6 +648,14 @@
   event->ignore(); // don't let the event propagate to the base class
 }
 
+#ifdef AUTOUPDATE
+void
+ChronoShareGui::checkForUpdates()
+{
+  m_sparkle.checkForUpdates();
+}
+#endif // AUTOUPDATE
+
 } // namespace chronoshare
 } // namespace ndn
 
diff --git a/gui/chronosharegui.hpp b/gui/chronosharegui.hpp
index c23fcf9..d80e8f6 100644
--- a/gui/chronosharegui.hpp
+++ b/gui/chronosharegui.hpp
@@ -42,13 +42,12 @@
 #include "server.hpp"
 #endif // Q_MOC_RUN
 
-#if __APPLE__ && HAVE_SPARKLE
-#define SPARKLE_SUPPORTED 1
-#include "sparkle-auto-update.hpp"
-#endif
-
 #include <thread>
 
+#ifdef AUTOUPDATE
+#include "osx-auto-update-sparkle.hpp"
+#endif // AUTOUPDATE
+
 namespace ndn {
 namespace chronoshare {
 
@@ -105,8 +104,10 @@
   void
   changeSettings();
 
+#ifdef AUTOUPDATE
   void
-  onCheckForUpdates();
+  checkForUpdates();
+#endif // AUTOUPDATE
 
 private:
   void
@@ -158,7 +159,6 @@
   QAction* m_viewSettings; // chronoShare settings
   QAction* m_changeFolder; // change the shared folder action
   QAction* m_quitProgram;  // quit program action
-  QAction* m_checkForUpdates;
   QAction* m_openWeb;
   QMenu* m_recentFilesMenu;
   QAction* m_fileActions[5];
@@ -181,9 +181,6 @@
   QLabel* label;
   QVBoxLayout* mainLayout;
 
-#ifdef SPARKLE_SUPPORTED
-  AutoUpdate* m_autoUpdate;
-#endif
   // QString m_settingsFilePath; // settings file path
   // QString m_settings;
 
@@ -194,6 +191,11 @@
   std::unique_ptr<Face> m_face;
   std::unique_ptr<FsWatcher> m_watcher;
   std::unique_ptr<Dispatcher> m_dispatcher;
+
+#ifdef AUTOUPDATE
+  QAction* m_checkForUpdates;
+  OsxAutoUpdateSparkle m_sparkle;
+#endif // AUTOUPDATE
 };
 
 } // namespace chronoshare
diff --git a/gui/osx-auto-update-sparkle.hpp b/gui/osx-auto-update-sparkle.hpp
new file mode 100644
index 0000000..bf2bfa7
--- /dev/null
+++ b/gui/osx-auto-update-sparkle.hpp
@@ -0,0 +1,54 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017, Regents of the University of California.
+ *
+ * This file is part of ChronoShare, a decentralized file sharing application over NDN.
+ *
+ * ChronoShare is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ChronoShare 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 General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ChronoShare, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ChronoShare authors and contributors.
+ */
+
+#ifndef NCC_OSX_AUTO_UPDATE_SPARKLE_HPP
+#define NCC_OSX_AUTO_UPDATE_SPARKLE_HPP
+
+#include "core/chronoshare-config.hpp"
+
+#ifndef OSX_BUILD
+#error "Cannot be included for non-OSX build"
+#endif // OSX_BUILD
+
+#include <string>
+#include <ndn-cxx/util/backports.hpp>
+
+namespace ndn {
+namespace chronoshare {
+
+class OsxAutoUpdateSparkle
+{
+public:
+  OsxAutoUpdateSparkle(const std::string& updateUrl);
+
+  ~OsxAutoUpdateSparkle();
+
+  void
+  checkForUpdates();
+
+private:
+  class Impl;
+  unique_ptr<Impl> m_impl;
+};
+
+} // namespace chronoshare
+} // namespace ndn
+
+#endif // NCC_OSX_AUTO_UPDATE_SPARKLE_HPP
diff --git a/gui/osx-auto-update-sparkle.mm b/gui/osx-auto-update-sparkle.mm
new file mode 100644
index 0000000..e3e3c3e
--- /dev/null
+++ b/gui/osx-auto-update-sparkle.mm
@@ -0,0 +1,61 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017, Regents of the University of California.
+ *
+ * This file is part of ChronoShare, a decentralized file sharing application over NDN.
+ *
+ * ChronoShare is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ChronoShare 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 General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ChronoShare, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ChronoShare authors and contributors.
+ */
+
+#include "osx-auto-update-sparkle.hpp"
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#import <Sparkle/Sparkle.h>
+
+namespace ndn {
+namespace chronoshare {
+
+class OsxAutoUpdateSparkle::Impl
+{
+public:
+  SUUpdater* m_updater;
+};
+
+
+OsxAutoUpdateSparkle::OsxAutoUpdateSparkle(const std::string& updateUrl)
+  : m_impl(make_unique<Impl>())
+{
+  m_impl->m_updater = [[SUUpdater sharedUpdater] retain];
+  NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:updateUrl.data()]];
+  [m_impl->m_updater setFeedURL:url];
+  [m_impl->m_updater setAutomaticallyChecksForUpdates:YES];
+  [m_impl->m_updater setUpdateCheckInterval:86400];
+}
+
+OsxAutoUpdateSparkle::~OsxAutoUpdateSparkle()
+{
+  [m_impl->m_updater release];
+  // presummably SUUpdater handles garbage collection
+}
+
+void
+OsxAutoUpdateSparkle::checkForUpdates()
+{
+  //[m_impl->m_updater checkForUpdatesInBackground];
+  [m_impl->m_updater checkForUpdates:nil];
+}
+
+} // namespace chronoshare
+} // namespace ndn
diff --git a/osx/auto-update/auto-update.hpp b/osx/auto-update/auto-update.hpp
deleted file mode 100644
index 24c6ad4..0000000
--- a/osx/auto-update/auto-update.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2016, Regents of the University of California.
- *
- * This file is part of ChronoShare, a decentralized file sharing application over NDN.
- *
- * ChronoShare is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * ChronoShare 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 General Public License for more details.
- *
- * You should have received copies of the GNU General Public License along with
- * ChronoShare, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ChronoShare authors and contributors.
- */
-
-#ifndef AUTO_UPDATE_H
-#define AUTO_UPDATE_H
-class AutoUpdate
-{
-public:
-  virtual ~AutoUpdate(){};
-  virtual void
-  checkForUpdates() = 0;
-};
-#endif
diff --git a/osx/auto-update/sparkle-auto-update.mm b/osx/auto-update/sparkle-auto-update.mm
deleted file mode 100644
index d64079b..0000000
--- a/osx/auto-update/sparkle-auto-update.mm
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2016, Regents of the University of California.
- *
- * This file is part of ChronoShare, a decentralized file sharing application over NDN.
- *
- * ChronoShare is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * ChronoShare 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 General Public License for more details.
- *
- * You should have received copies of the GNU General Public License along with
- * ChronoShare, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ChronoShare authors and contributors.
- */
-
-#include "sparkle-auto-update.hpp"
-#import <AppKit/AppKit.h>
-#import <Foundation/Foundation.h>
-#import <Sparkle/Sparkle.h>
-
-#include "logging.hpp"
-
-_LOG_INIT(SparkeAutoUpdate);
-
-class SparkleAutoUpdate::Private
-{
-public:
-  SUUpdater* updater;
-};
-
-SparkleAutoUpdate::SparkleAutoUpdate(const QString& updateUrl)
-{
-  d = new Private;
-  d->updater = [[SUUpdater sharedUpdater] retain];
-  NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:updateUrl.toUtf8().data()]];
-  [d->updater setFeedURL:url];
-  [d->updater setAutomaticallyChecksForUpdates:YES];
-  [d->updater setUpdateCheckInterval:86400];
-}
-
-SparkleAutoUpdate::~SparkleAutoUpdate()
-{
-  [d->updater release];
-  delete d;
-  // presummably SUUpdater handles garbage collection
-}
-
-void
-SparkleAutoUpdate::checkForUpdates()
-{
-  //[d->updater checkForUpdatesInBackground];
-  [d->updater checkForUpdates:nil];
-  _LOG_DEBUG("++++++++ checking update +++++");
-}
diff --git a/chronoshare.icns b/res/chronoshare.icns
similarity index 100%
rename from chronoshare.icns
rename to res/chronoshare.icns
Binary files differ
diff --git a/res/ndn_sparkle_pub.pem b/res/ndn_sparkle_pub.pem
new file mode 100644
index 0000000..f6e6286
--- /dev/null
+++ b/res/ndn_sparkle_pub.pem
@@ -0,0 +1,36 @@
+-----BEGIN PUBLIC KEY-----
+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
+kdJFTGXTVaoTjDtOBgg=
+-----END PUBLIC KEY-----
diff --git a/sparkle-appcast.xml b/sparkle-appcast.xml
new file mode 100644
index 0000000..60adc74
--- /dev/null
+++ b/sparkle-appcast.xml
@@ -0,0 +1,10 @@
+<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
+  <channel>
+    <title>ChronoShare Changelog</title>
+    <link>
+      https://named-data.net/binaries/ChronoShare/sparkle-appcast.xml
+    </link>
+    <description>Most recent changes with links to updates.</description>
+    <language>en</language>
+  </channel>
+</rss>
diff --git a/src/Info.plist.in b/src/Info.plist.in
new file mode 100644
index 0000000..500af34
--- /dev/null
+++ b/src/Info.plist.in
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+    <key>CFBundleDevelopmentRegion</key>
+    <string>English</string>
+    <key>CFBundleExecutable</key>
+    <string>ChronoShare</string>
+    <key>CFBundleIconFile</key>
+    <string>chronoshare.icns</string>
+    <key>CFBundleIdentifier</key>
+    <string>edu.ucla.cs.irl.Chronoshare</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleName</key>
+    <string>ChronoShare</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleShortVersionString</key>
+    <string>@VERSION@</string>
+    <key>LSMinimumSystemVersion</key>
+    <string>10.6</string>
+    <key>CFBundleVersion</key>
+    <string>@VERSION@</string>
+    <key>NSMainNibFile</key>
+    <string>MainMenu</string>
+    <key>NSPrincipalClass</key>
+    <string>NSApplication</string>
+    <key>NSHighResolutionCapable</key>
+    <string>True</string>
+    <key>LSUIElement</key>
+    <string>1</string>
+    <key>SUFeedURL</key>
+    <string>@APPCAST@</string>
+    <key>SUPublicDSAKeyFile</key>
+    <string>ndn_sparkle_pub.pem</string>
+</dict>
+</plist>
diff --git a/tests/wscript b/tests/wscript
index d624a7c..65adc70 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -41,4 +41,4 @@
         defines=['UNIT_TEST_CONFIG_PATH=\"%s/tmp-files/\"' % (bld.bldnode)],
         includes='.. ../src .')
 
-    bld.recurse('integrated-tests')
\ No newline at end of file
+    bld.recurse('integrated-tests')
diff --git a/wscript b/wscript
index 5199d2c..0799117 100644
--- a/wscript
+++ b/wscript
@@ -1,6 +1,7 @@
 # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-VERSION='1.0'
+VERSION='0.1.0'
 APPNAME='ChronoShare'
+APPCAST='https://named-data.net/binaries/ChronoShare/sparkle-appcast.xml'
 
 from waflib import Logs, Utils, Task, TaskGen
 
@@ -77,6 +78,15 @@
 
     conf.define('SYSCONFDIR', conf.env['SYSCONFDIR'])
 
+    conf.define('CHRONOSHARE_VERSION', VERSION)
+    conf.define('CHRONOSHARE_APPCAST', APPCAST)
+
+    if Utils.unversioned_sys_platform() == "darwin":
+        conf.define('OSX_BUILD', 1)
+        conf.env['AUTOUPDATE'] = conf.options.autoupdate
+        if conf.env['AUTOUPDATE']:
+            conf.define('AUTOUPDATE', 1)
+
     conf.write_config_header('core/chronoshare-config.hpp')
 
 def build(bld):
@@ -130,13 +140,13 @@
         export_includes='gui',
         )
 
-    gui = bld(
+    app = bld(
         target = "ChronoShare",
         features = "qt5 cxx cxxprogram html_resources",
         defines = "WAF",
-        source = bld.path.ant_glob(['gui/main.cpp']),
+        source = bld.path.ant_glob(['gui/main.cpp']) + ['gui/images.qrc'],
         includes = "fs-watcher gui src adhoc server . ",
-        use = "fs-watcher chronoshare http_server chronoshare_gui QT5CORE QT5GUI QT5WIDGETS",
+        use = "chronoshare_gui",
         html_resources = bld.path.find_dir("gui/html").ant_glob([
                 '**/*.js', '**/*.png', '**/*.css',
                 '**/*.html', '**/*.gif', '**/*.ico'
@@ -144,55 +154,30 @@
         export_includes='gui',
     )
 
-#     if Utils.unversioned_sys_platform() == "darwin":
-#         app_plist = '''<?xml version="1.0" encoding="UTF-8"?>
-# <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
-# <plist version="0.9">
-# <dict>
-#     <key>CFBundlePackageType</key>
-#     <string>APPL</string>
-#     <key>CFBundleIconFile</key>
-#     <string>chronoshare.icns</string>
-#     <key>CFBundleGetInfoString</key>
-#     <string>Created by Waf</string>
-#     <key>CFBundleIdentifier</key>
-#     <string>edu.ucla.cs.irl.Chronoshare</string>
-#     <key>CFBundleSignature</key>
-#     <string>????</string>
-#     <key>NOTE</key>
-#     <string>THIS IS A GENERATED FILE, DO NOT MODIFY</string>
-#     <key>CFBundleExecutable</key>
-#     <string>%s</string>
-#     <key>LSUIElement</key>
-#     <string>1</string>
-#     <key>SUPublicDSAKeyFile</key>
-#     <string>dsa_pub.pem</string>
-#     <key>CFBundleIconFile</key>
-#     <string>chronoshare.icns</string>
-# </dict>
-# </plist>'''
-#         qt.mac_app = "ChronoShare.app"
-#         qt.mac_plist = app_plist % "ChronoShare"
-#         qt.mac_resources = 'chronoshare.icns'
-#         qt.use += " OSX_FOUNDATION OSX_COREWLAN adhoc"
+    if Utils.unversioned_sys_platform() == "darwin":
+        bld(features="subst",
+            source='src/Info.plist.in',
+            target='src/Info.plist',
+            install_path=None,
+            VERSION=VERSION,
+            APPCAST=APPCAST)
 
-#         if bld.env['HAVE_SPARKLE']:
-#             qt.use += " OSX_SPARKLE"
-#             qt.source += ["osx/auto-update/sparkle-auto-update.mm"]
-#             qt.includes += " osx/auto-update"
-#             if bld.env['HAVE_LOCAL_SPARKLE']:
-#                 qt.mac_frameworks = "osx/Frameworks/Sparkle.framework"
+        if bld.env['AUTOUPDATE']:
+            chronoshare_gui.source += bld.path.ant_glob(['gui/osx-*.mm'])
+            chronoshare_gui.use += " OSX_FOUNDATION OSX_SPARKLE"
+        app.mac_app = True
+        app.mac_plist = 'src/Info.plist'
+        app.mac_files = [i.path_from(bld.path) for i in bld.path.ant_glob('res/**/*', excl='**/*.ai')]
 
-#     if Utils.unversioned_sys_platform() == "linux":
-#         bld(
-#             features = "process_in",
-#             target = "ChronoShare.desktop",
-#             source = "ChronoShare.desktop.in",
-#             install_prefix = "${DATADIR}/applications",
-#             )
-#         bld.install_files("${DATADIR}/applications", "ChronoShare.desktop")
-#         bld.install_files("${DATADIR}/ChronoShare", "gui/images/chronoshare-big.png")
-    Logs.error("ChronoShare app compilation is temporary disabled")
+    if Utils.unversioned_sys_platform() == "linux":
+        bld(
+            features = "process_in",
+            target = "ChronoShare.desktop",
+            source = "ChronoShare.desktop.in",
+            install_prefix = "${DATADIR}/applications",
+            )
+        bld.install_files("${DATADIR}/applications", "ChronoShare.desktop")
+        bld.install_files("${DATADIR}/ChronoShare", "gui/images/chronoshare-big.png")
 
     cmdline = bld(
         target = "csd",