blob: 23102a4f2a19cc5f4db43a0cb3112dd258bc352c [file] [log] [blame]
taylorchuc27dd482014-05-17 20:06:49 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev37667752017-02-02 13:52:12 -08003 * Copyright (c) 2013-2017, Regents of the University of California,
taylorchuc27dd482014-05-17 20:06:49 -07004 *
5 * This file is part of NFD Control Center. See AUTHORS.md for complete list of NFD
6 * authors and contributors.
7 *
8 * NFD Control Center is free software: you can redistribute it and/or modify it under the
9 * terms of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NFD Control Center is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 *
Qi Zhao0e043e52016-12-05 18:27:09 -080016 * You should have received a copy of the GNU General Public License along with NFD
taylorchuc27dd482014-05-17 20:06:49 -070017 * Control Center, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
taylorchuc27dd482014-05-17 20:06:49 -070020#include "tray-menu.hpp"
Alexander Afanasyev37667752017-02-02 13:52:12 -080021#include "tray-menu.moc"
taylorchuc27dd482014-05-17 20:06:49 -070022
Qi Zhaoae9c4312017-02-02 11:36:12 -080023#include <chrono>
24#include <functional>
25
taylorchuc27dd482014-05-17 20:06:49 -070026#include <ndn-cxx/face.hpp>
27#include <ndn-cxx/interest.hpp>
Qi Zhaoae9c4312017-02-02 11:36:12 -080028#include <boost/algorithm/string/replace.hpp>
taylorchuc27dd482014-05-17 20:06:49 -070029
taylorchuc27dd482014-05-17 20:06:49 -070030#ifdef OSX_BUILD
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070031#define CONNECT_ICON ":/res/icon-connected-black.png"
32#define DISCONNECT_ICON ":/res/icon-disconnected-black.png"
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070033
34#include <Security/Authorization.h>
35#include <Security/AuthorizationTags.h>
Qi Zhao3615a102017-02-02 20:38:34 -080036
37#include "build/NFD/build/core/version.hpp"
38#include "build/ndn-tools/build/core/version.cpp"
39
taylorchuc27dd482014-05-17 20:06:49 -070040#else
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070041#define CONNECT_ICON ":/res/icon-connected-white.png"
42#define DISCONNECT_ICON ":/res/icon-disconnected-white.png"
Qi Zhao3615a102017-02-02 20:38:34 -080043
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070044#endif // OSX_BUILD
taylorchuc27dd482014-05-17 20:06:49 -070045
Qi Zhao3615a102017-02-02 20:38:34 -080046#include <ndn-cxx/version.hpp>
47
taylorchuc27dd482014-05-17 20:06:49 -070048namespace ndn {
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080049namespace ncc {
taylorchuc27dd482014-05-17 20:06:49 -070050
Qi Zhaoae9c4312017-02-02 11:36:12 -080051/**
52 * @brief Maximum number of lines that can show up in auto-config status tab view
53 */
54const int MAX_LINES_IN_AUTOCONF_STATUS = 100;
55
56#ifdef OSX_BUILD
57const QString AUTO_START_SUFFIX = "Library/LaunchAgents/net.named-data.control-center.plist";
58#endif // OSX_BUILD
59
Alexander Afanasyev81509f32016-03-21 17:02:38 -070060TrayMenu::TrayMenu(QQmlContext* context, Face& face)
Alexander Afanasyev4086d512014-07-11 15:56:33 -070061 : m_context(context)
62 , m_isNfdRunning(false)
Yingdi Yu53c11c12016-03-20 12:56:49 -070063 , m_menu(new QMenu(this))
64 , m_entryPref(new QAction("Preferences...", m_menu))
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070065 , m_entrySec(new QAction("Security...", m_menu))
Qi Zhaoae9c4312017-02-02 11:36:12 -080066 , m_acProc(nullptr)
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080067 , m_settings(new QSettings())
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070068#ifdef OSX_BUILD
69 , m_entryEnableCli(new QAction("Enable Command Terminal Usage...", m_menu))
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080070 , m_checkForUpdates(new QAction("Check for updates", m_menu))
Alexander Afanasyeve095ed12017-02-04 23:09:55 -080071 , m_sparkle(NCC_APPCAST)
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070072#endif
Yingdi Yu53c11c12016-03-20 12:56:49 -070073 , m_entryQuit(new QAction("Quit", m_menu))
Yingdi Yu1f824642016-03-20 17:07:22 -070074 , m_keyViewerDialog(new ncc::KeyViewerDialog)
Alexander Afanasyev81509f32016-03-21 17:02:38 -070075 , m_face(face)
Yingdi Yu53c11c12016-03-20 12:56:49 -070076{
77 connect(m_entryPref, SIGNAL(triggered()), this, SIGNAL(showApp()));
Yingdi Yu1f824642016-03-20 17:07:22 -070078 connect(m_entrySec, SIGNAL(triggered()), m_keyViewerDialog, SLOT(present()));
Yingdi Yu53c11c12016-03-20 12:56:49 -070079 connect(m_entryQuit, SIGNAL(triggered()), this, SLOT(quitApp()));
taylorchuc27dd482014-05-17 20:06:49 -070080
Alexander Afanasyev4086d512014-07-11 15:56:33 -070081 connect(this, SIGNAL(nfdActivityUpdate(bool)), this, SLOT(updateNfdActivityIcon(bool)),
82 Qt::QueuedConnection);
83
Qi Zhao3615a102017-02-02 20:38:34 -080084 QString nccVersion = QString(NCC_VERSION) + " (ndn-cxx: " + NDN_CXX_VERSION_BUILD_STRING +
85 ", NFD: " + NFD_VERSION_BUILD_STRING +
86 ", ndn-tools: " + ::ndn::tools::VERSION +
87 ")";
88
89 m_context->setContextProperty("nccVersion", nccVersion);
90
Yingdi Yu53c11c12016-03-20 12:56:49 -070091 m_menu->addAction(m_entryPref);
92 m_menu->addAction(m_entrySec);
Qi Zhaoae9c4312017-02-02 11:36:12 -080093
susmit50607912016-03-21 12:00:15 -070094#ifdef OSX_BUILD
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080095 connect(m_entryEnableCli, SIGNAL(triggered()), this, SLOT(enableCli()));
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070096 m_menu->addAction(m_entryEnableCli);
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080097
98 connect(m_checkForUpdates, SIGNAL(triggered()), this, SLOT(checkForUpdates()));
99 m_menu->addAction(m_checkForUpdates);
susmit50607912016-03-21 12:00:15 -0700100#endif
Qi Zhaoae9c4312017-02-02 11:36:12 -0800101
Yingdi Yu53c11c12016-03-20 12:56:49 -0700102 m_menu->addAction(m_entryQuit);
103 m_tray = new QSystemTrayIcon(this);
104 m_tray->setContextMenu(m_menu);
Yingdi Yu53c11c12016-03-20 12:56:49 -0700105 m_tray->setIcon(QIcon(DISCONNECT_ICON));
106 m_tray->show();
Qi Zhaoae9c4312017-02-02 11:36:12 -0800107
108 // delaying for the case when NFD is already started (to avoid starting / to avoid starting autoconfig
109 if (isNfdAutoStartEnabled()) {
110 scheduleDelayedTask(std::chrono::seconds(5), [this] {
111 if (!m_isNfdRunning) {
112 startNfd();
113 }
114 });
Qi Zhao86f2b212016-12-06 12:44:16 -0800115 }
taylorchuc27dd482014-05-17 20:06:49 -0700116}
117
118TrayMenu::~TrayMenu()
119{
Qi Zhaoae9c4312017-02-02 11:36:12 -0800120 // delete for all new's
taylorchuc27dd482014-05-17 20:06:49 -0700121}
122
Qi Zhaoae9c4312017-02-02 11:36:12 -0800123////////////////////////////////////////////////////////////////////////////////
124// NFD Control Center start on login
Qi Zhao86f2b212016-12-06 12:44:16 -0800125
126Q_INVOKABLE bool
Qi Zhaoae9c4312017-02-02 11:36:12 -0800127TrayMenu::isNccAutoStartEnabled() const
Qi Zhao86f2b212016-12-06 12:44:16 -0800128{
Qi Zhaoae9c4312017-02-02 11:36:12 -0800129 QFileInfo file(QDir::home().path() + "/" + AUTO_START_SUFFIX);
130 return file.exists() && file.isFile();
Qi Zhao86f2b212016-12-06 12:44:16 -0800131}
132
133Q_INVOKABLE void
Qi Zhaoae9c4312017-02-02 11:36:12 -0800134TrayMenu::enableDisableNccAutoStart(bool isEnabled)
Qi Zhao86f2b212016-12-06 12:44:16 -0800135{
Qi Zhaoae9c4312017-02-02 11:36:12 -0800136 if (isEnabled) {
137 QFile file(QDir::home().path() + "/" + AUTO_START_SUFFIX);
138 file.open(QIODevice::WriteOnly);
139
140 std::string plist = R"PLIST(<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
141<?xml version="1.0" encoding="UTF-8"?>
142<plist version="1.0">
143 <dict>
144 <key>Label</key>
145 <string>net.named-data.control-center</string>
146 <key>ProgramArguments</key>
147 <array>
148 <string>%%PATH%%</string>
149 </array>
150 <key>RunAtLoad</key>
151 <true/>
152 <key>KeepAlive</key>
153 <false/>
154 </dict>
155</plist>
156)PLIST"; //"
157 boost::replace_all(plist, "%%PATH%%", QCoreApplication::applicationFilePath().toStdString());
158 file.write(plist.data(), plist.size());
159 file.close();
160 } else {
161 QFile::remove(QDir::home().path() + "/" + AUTO_START_SUFFIX);
Qi Zhao86f2b212016-12-06 12:44:16 -0800162 }
taylorchuc27dd482014-05-17 20:06:49 -0700163}
164
Qi Zhaoae9c4312017-02-02 11:36:12 -0800165////////////////////////////////////////////////////////////////////////////////
166// NFD start on launch
taylorchuc27dd482014-05-17 20:06:49 -0700167
Qi Zhaoae9c4312017-02-02 11:36:12 -0800168Q_INVOKABLE bool
169TrayMenu::isNfdAutoStartEnabled() const
taylorchuc27dd482014-05-17 20:06:49 -0700170{
Qi Zhaoae9c4312017-02-02 11:36:12 -0800171 return m_settings->value("ENABLE_AUTO_START", false).toBool();
taylorchuc27dd482014-05-17 20:06:49 -0700172}
173
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700174Q_INVOKABLE void
Qi Zhaoae9c4312017-02-02 11:36:12 -0800175TrayMenu::enableDisableNfdAutoStart(bool isEnabled)
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700176{
Qi Zhaoae9c4312017-02-02 11:36:12 -0800177 m_settings->setValue("ENABLE_AUTO_START", isEnabled);
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700178 if (!m_isNfdRunning) {
179 startNfd();
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700180 }
181}
182
taylorchuc27dd482014-05-17 20:06:49 -0700183void
184TrayMenu::startNfd()
185{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700186#ifdef OSX_BUILD
187 QProcess* proc = new QProcess();
188 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
Qi Zhaoae9c4312017-02-02 11:36:12 -0800189 proc->startDetached((QCoreApplication::applicationDirPath() + "/../Platform/nfd"),
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700190 QStringList()
191 << "--config"
Qi Zhaoae9c4312017-02-02 11:36:12 -0800192 << (QCoreApplication::applicationDirPath() + "/../etc/ndn/nfd.conf"));
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700193#endif
taylorchuc27dd482014-05-17 20:06:49 -0700194}
195
196void
197TrayMenu::stopNfd()
198{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700199#ifdef OSX_BUILD
200 QProcess* proc = new QProcess();
201 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
202 proc->startDetached("killall", QStringList() << "nfd");
203#endif
taylorchuc27dd482014-05-17 20:06:49 -0700204}
205
Qi Zhaoae9c4312017-02-02 11:36:12 -0800206////////////////////////////////////////////////////////////////////////////////
207// NDN Autoconfig
208
209Q_INVOKABLE bool
210TrayMenu::isNdnAutoConfigEnabled() const
211{
212 return m_settings->value("ENABLE_NDN_AUTO_CONFIG", false).toBool();
213}
214
215Q_INVOKABLE void
216TrayMenu::enableDisableNdnAutoConfig(bool isEnabled)
217{
218 m_settings->setValue("ENABLE_NDN_AUTO_CONFIG", isEnabled);
219
220 if (isEnabled) {
221 startNdnAutoConfig();
222 }
223 else {
224 stopNdnAutoConfig();
225 }
226}
227
228void
229TrayMenu::startNdnAutoConfig()
230{
231 if (m_acProc != nullptr) {
232 return;
233 }
234
235 stopNdnAutoConfig(false); // Make sure no more than one auto-config process exist
236
237 if (!m_isNfdRunning) {
238 return;
239 }
240
241 m_acProc = new QProcess();
242
243 scheduleDelayedTask(std::chrono::seconds(2), [this] {
244 appendNdnAutoConfigStatus("NDN auto configuration starting...\n");
245 m_acProc->start(QCoreApplication::applicationDirPath() + "/../Platform/ndn-autoconfig",
246 QStringList() << "--daemon");
247 connect(m_acProc, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
248 connect(m_acProc, SIGNAL(readyReadStandardError()), this, SLOT(processOutput()));
249 });
250}
251
252void
253TrayMenu::stopNdnAutoConfig(bool appendStatus)
254{
255 m_acProc = nullptr;
256 QProcess* proc = new QProcess();
257 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
258 proc->startDetached("killall", QStringList() << "ndn-autoconfig");
259 if (appendStatus) {
260 appendNdnAutoConfigStatus("NDN auto configuration stopped\n");
261 }
262}
263
264void
265TrayMenu::appendNdnAutoConfigStatus(const QString& message)
266{
267 if (message == "") {
268 return;
269 }
270 if (m_ndnAutoConfigMsg.count("\n") > MAX_LINES_IN_AUTOCONF_STATUS) {
271 int end = m_ndnAutoConfigMsg.indexOf("\n");
272 m_ndnAutoConfigMsg.remove(0, end + 1);
273 }
274 m_ndnAutoConfigMsg.append(message);
275
276 m_context->setContextProperty("ndnAutoConfigText", m_ndnAutoConfigMsg);
277}
278
279void
280TrayMenu::processOutput()
281{
282 if (m_acProc == nullptr) {
283 return;
284 }
285 appendNdnAutoConfigStatus(m_acProc->readAllStandardOutput());
286 appendNdnAutoConfigStatus(m_acProc->readAllStandardError());
287}
288
289////////////////////////////////////////////////////////////////////////////////
290// NFD stop on shutdown
291
292Q_INVOKABLE bool
293TrayMenu::isNfdStopOnExitEnabled() const
294{
295 return m_settings->value("ENABLE_SHUTDOWN", false).toBool();
296}
297
298Q_INVOKABLE void
299TrayMenu::enableDisableNfdStopOnExit(bool isEnabled)
300{
301 m_settings->setValue("ENABLE_SHUTDOWN", isEnabled);
302}
303
304////////////////////////////////////////////////////////////////////////////////
305// Misc
306
307void
308TrayMenu::quitApp()
309{
310 if (isNfdStopOnExitEnabled()) {
311 stopNdnAutoConfig();
312 stopNfd();
313 }
314 QCoreApplication::exit(0);
315}
316
susmit4fe3cb92016-03-20 17:08:41 -0700317Q_INVOKABLE void
318TrayMenu::addDeleteRoute()
319{
320 addRoute();
321}
322
323Q_INVOKABLE void
324TrayMenu::addRoute()
325{
326 std::cout << "Adding route" << std::endl;
327 QString cmd = "nfdc register /test tcp4://localhost";
328 QProcess *addNewRoute = new QProcess();
329 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
330 addNewRoute->start("bash", QStringList() << "-c" << cmd);
331 std::cout << "Done" << std::endl;
susmit4fe3cb92016-03-20 17:08:41 -0700332}
333
334void
335TrayMenu::deleteRoute()
336{
337 std::cout << "Deleting route" << std::endl;
338 QString cmd = "nfdc unregister /test tcp4://localhost";
339 QProcess *addNewRoute = new QProcess();
340 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
341 addNewRoute->start("bash", QStringList() << "-c" << cmd);
342 std::cout << "Done" << std::endl;
susmit4fe3cb92016-03-20 17:08:41 -0700343}
344
taylorchuc27dd482014-05-17 20:06:49 -0700345void
346TrayMenu::updateNfdActivityIcon(bool isActive)
347{
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700348 m_isNfdRunning = isActive;
349
taylorchuc27dd482014-05-17 20:06:49 -0700350 if (isActive) {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700351 m_tray->setIcon(QIcon(CONNECT_ICON));
Qi Zhaoae9c4312017-02-02 11:36:12 -0800352 if (isNdnAutoConfigEnabled()) {
353 startNdnAutoConfig();
354 }
taylorchuc27dd482014-05-17 20:06:49 -0700355 }
356 else {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700357 m_tray->setIcon(QIcon(DISCONNECT_ICON));
taylorchuc27dd482014-05-17 20:06:49 -0700358 }
359}
360
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700361void
362TrayMenu::enableCli()
363{
364#ifdef OSX_BUILD
Qi Zhaoae9c4312017-02-02 11:36:12 -0800365 QProcess* proc = new QProcess();
366 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700367
Qi Zhaoae9c4312017-02-02 11:36:12 -0800368 proc->start("osascript", QStringList()
369 << "-e"
370 << "do shell script \""
371 "/bin/mkdir -vp /usr/local/bin; "
372 "/bin/ln -s -f '" + QCoreApplication::applicationDirPath() +
373 "/../Resources/ndn" + "' /usr/local/bin/ndn;"
374 "\" with administrator privileges");
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700375#endif
376}
377
Alexander Afanasyevfda42a82017-02-01 18:03:39 -0800378#ifdef OSX_BUILD
379void
380TrayMenu::checkForUpdates()
381{
382 m_sparkle.checkForUpdates();
383}
384#endif // OSX_BUILD
385
Qi Zhaoae9c4312017-02-02 11:36:12 -0800386void
387TrayMenu::scheduleDelayedTask(std::chrono::milliseconds delays, const std::function<void()>& task)
388{
389 auto timer = new QTimer();
390 timer->setSingleShot(true);
391 timer->setInterval(delays);
392 connect(timer, &QTimer::timeout,
393 [task, timer] {
394 task();
395 timer->deleteLater();
396 });
397 timer->start();
398}
399
Alexander Afanasyevfda42a82017-02-01 18:03:39 -0800400} // namespace ncc
taylorchuc27dd482014-05-17 20:06:49 -0700401} // namespace ndn