blob: 2ec3cb4a85a0dbec8171a7ee4555df49a32b116c [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
23#include <ndn-cxx/face.hpp>
24#include <ndn-cxx/interest.hpp>
25
taylorchuc27dd482014-05-17 20:06:49 -070026#ifdef OSX_BUILD
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070027#define CONNECT_ICON ":/res/icon-connected-black.png"
28#define DISCONNECT_ICON ":/res/icon-disconnected-black.png"
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070029
30#include <Security/Authorization.h>
31#include <Security/AuthorizationTags.h>
taylorchuc27dd482014-05-17 20:06:49 -070032#else
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070033#define CONNECT_ICON ":/res/icon-connected-white.png"
34#define DISCONNECT_ICON ":/res/icon-disconnected-white.png"
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070035#endif // OSX_BUILD
taylorchuc27dd482014-05-17 20:06:49 -070036
taylorchuc27dd482014-05-17 20:06:49 -070037namespace ndn {
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080038namespace ncc {
taylorchuc27dd482014-05-17 20:06:49 -070039
Alexander Afanasyev81509f32016-03-21 17:02:38 -070040TrayMenu::TrayMenu(QQmlContext* context, Face& face)
Alexander Afanasyev4086d512014-07-11 15:56:33 -070041 : m_context(context)
42 , m_isNfdRunning(false)
Yingdi Yu53c11c12016-03-20 12:56:49 -070043 , m_menu(new QMenu(this))
44 , m_entryPref(new QAction("Preferences...", m_menu))
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070045 , m_entrySec(new QAction("Security...", m_menu))
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080046 , m_acProc(new QProcess())
47 , m_settings(new QSettings())
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070048#ifdef OSX_BUILD
49 , m_entryEnableCli(new QAction("Enable Command Terminal Usage...", m_menu))
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080050 , m_checkForUpdates(new QAction("Check for updates", m_menu))
51 , m_sparkle("https://irl.cs.ucla.edu/~cawka/ndn-control-center.xml")
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070052#endif
Yingdi Yu53c11c12016-03-20 12:56:49 -070053 , m_entryQuit(new QAction("Quit", m_menu))
Yingdi Yu1f824642016-03-20 17:07:22 -070054 , m_keyViewerDialog(new ncc::KeyViewerDialog)
Alexander Afanasyev81509f32016-03-21 17:02:38 -070055 , m_face(face)
Yingdi Yu53c11c12016-03-20 12:56:49 -070056{
57 connect(m_entryPref, SIGNAL(triggered()), this, SIGNAL(showApp()));
Qi Zhao86f2b212016-12-06 12:44:16 -080058 connect(this, SIGNAL(showApp()), this, SLOT(showPref()));
Yingdi Yu1f824642016-03-20 17:07:22 -070059 connect(m_entrySec, SIGNAL(triggered()), m_keyViewerDialog, SLOT(present()));
Yingdi Yu53c11c12016-03-20 12:56:49 -070060 connect(m_entryQuit, SIGNAL(triggered()), this, SLOT(quitApp()));
taylorchuc27dd482014-05-17 20:06:49 -070061
Alexander Afanasyev4086d512014-07-11 15:56:33 -070062 connect(this, SIGNAL(nfdActivityUpdate(bool)), this, SLOT(updateNfdActivityIcon(bool)),
63 Qt::QueuedConnection);
64
65 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Start NFD")));
Qi Zhao86f2b212016-12-06 12:44:16 -080066 m_context->setContextProperty("acText", QVariant::fromValue(QString("")));
taylorchuc27dd482014-05-17 20:06:49 -070067
Yingdi Yu53c11c12016-03-20 12:56:49 -070068 m_menu->addAction(m_entryPref);
69 m_menu->addAction(m_entrySec);
susmit50607912016-03-21 12:00:15 -070070#ifdef OSX_BUILD
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080071 connect(m_entryEnableCli, SIGNAL(triggered()), this, SLOT(enableCli()));
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070072 m_menu->addAction(m_entryEnableCli);
Alexander Afanasyevfda42a82017-02-01 18:03:39 -080073
74 connect(m_checkForUpdates, SIGNAL(triggered()), this, SLOT(checkForUpdates()));
75 m_menu->addAction(m_checkForUpdates);
susmit50607912016-03-21 12:00:15 -070076#endif
Yingdi Yu53c11c12016-03-20 12:56:49 -070077 m_menu->addAction(m_entryQuit);
78 m_tray = new QSystemTrayIcon(this);
79 m_tray->setContextMenu(m_menu);
80 connect(m_tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
taylorchuc27dd482014-05-17 20:06:49 -070081 this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Yingdi Yu53c11c12016-03-20 12:56:49 -070082 m_tray->setIcon(QIcon(DISCONNECT_ICON));
83 m_tray->show();
Qi Zhao86f2b212016-12-06 12:44:16 -080084 if (isAutoConfigEnabled()) {
85 stopAutoConfig(); // Make sure no more than one auto-config process exist
86 QTimer* mTimer = new QTimer(this);
87 mTimer->setSingleShot(true);
88 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
89 mTimer->start(2000);
90 }
taylorchuc27dd482014-05-17 20:06:49 -070091}
92
93TrayMenu::~TrayMenu()
94{
95}
96
Qi Zhao86f2b212016-12-06 12:44:16 -080097void
98TrayMenu::appendMsg(QString &target, QString source)
taylorchuc27dd482014-05-17 20:06:49 -070099{
Qi Zhao86f2b212016-12-06 12:44:16 -0800100 int maxLine = 100; // Max line that will show in auto-config status tab view
101 if (target.count(QString("\n")) > maxLine) { // Only when target QString has more line than maxLine, it needs remove line
102 int end = target.indexOf(QString("\n"));
103 target.remove(0, end + 1); // Remove the first line of target
104 }
105 target.append(source);
106}
107
108void
109TrayMenu::showPref()
110{
111 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg)); // Update auto-config status tab view
112}
113
114void
115TrayMenu::processOutput()
116{
117 std::string msg = m_acProc->readAllStandardOutput().toStdString();
118 if (msg != "") {
119 appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
120 }
121 msg = m_acProc->readAllStandardError().toStdString();
122 if (msg != "") {
123 appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
124 }
125 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
126}
127
128Q_INVOKABLE bool
129TrayMenu::isAutoConfigEnabled()
130{
131 bool sAutoConfig = m_settings.value("main/auto-config", QVariant(false)).toBool();
132 return sAutoConfig;
133}
134
135void
136TrayMenu::startAutoConfig()
137{
138 if (m_isNfdRunning) {
139 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will start...\n"));
140 connect(m_acProc, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
141 connect(m_acProc, SIGNAL(readyReadStandardError()), this, SLOT(processOutput()));
142 m_acProc->start((QCoreApplication::applicationDirPath().toStdString() + "/../Platform/ndn-autoconfig").c_str(),
143 QStringList()
144 << "--daemon");
145 }
146}
147
148void
149TrayMenu::stopAutoConfig()
150{
151#ifdef OSX_BUILD
taylorchuc27dd482014-05-17 20:06:49 -0700152 QProcess* proc = new QProcess();
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700153 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
Qi Zhao86f2b212016-12-06 12:44:16 -0800154 proc->startDetached("killall", QStringList() << "ndn-autoconfig");
155#endif
156}
157
158Q_INVOKABLE void
159TrayMenu::startStopAutoConfig(bool autoConfig)
160{
161 if (m_isNfdRunning) {
162 if (autoConfig) {
163 stopAutoConfig(); // Make sure no more than one auto-config process exist
164 QTimer* mTimer = new QTimer(this);
165 mTimer->setSingleShot(true);
166 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
167 mTimer->start(2000);
168 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
169 m_settings.setValue("main/auto-config", true);
170 }
171 else {
172 stopAutoConfig();
173 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
174 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
175 m_settings.setValue("main/auto-config", false);
176 }
177 }
178 else { // No need to start or stop auto-config when NFD is not running, but it needs to update settings
179 if (autoConfig) {
180 m_settings.setValue("main/auto-config", true);
181 }
182 else {
183 m_settings.setValue("main/auto-config", false);
184 }
185 }
taylorchuc27dd482014-05-17 20:06:49 -0700186}
187
188void
189TrayMenu::quitApp()
190{
191 QCoreApplication::exit(0);
192}
193
194void
195TrayMenu::iconActivated(QSystemTrayIcon::ActivationReason reason)
196{
197 switch (reason) {
198 // case QSystemTrayIcon::Trigger:
199 // emit showApp();
200 // break;
201 case QSystemTrayIcon::Context:
202 break;
203 default:
204 break;
205 }
206}
207
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700208Q_INVOKABLE void
Qi Zhao86f2b212016-12-06 12:44:16 -0800209TrayMenu::startStopNfd(bool autoConfig)
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700210{
211 if (!m_isNfdRunning) {
212 startNfd();
Qi Zhao86f2b212016-12-06 12:44:16 -0800213 if (autoConfig) {
214 stopAutoConfig(); // Make sure no more than one auto-config process exist
215 QTimer* mTimer = new QTimer(this);
216 mTimer->setSingleShot(true);
217 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
218 mTimer->start(2000);
219 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
220 }
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700221 }
222 else {
223 stopNfd();
Qi Zhao86f2b212016-12-06 12:44:16 -0800224 stopAutoConfig();
225 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
226 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700227 }
228}
229
taylorchuc27dd482014-05-17 20:06:49 -0700230void
231TrayMenu::startNfd()
232{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700233#ifdef OSX_BUILD
234 QProcess* proc = new QProcess();
235 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
236 proc->startDetached((QCoreApplication::applicationDirPath().toStdString() + "/../Platform/nfd").c_str(),
237 QStringList()
238 << "--config"
Alexander Afanasyev964feb92016-03-22 13:03:11 -0700239 << (QCoreApplication::applicationDirPath().toStdString() + "/../etc/ndn/nfd.conf").c_str());
Qi Zhao86f2b212016-12-06 12:44:16 -0800240
241
242 // #endif
243 // QProcess * proc = new QProcess();
244 // connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
245 // #ifdef __linux__
246 // proc->start("gksudo", QStringList() << NFD_START_COMMAND);
247 // #else
248 // proc->start("osascript", QStringList()
249 // << "-e"
250 // << "do shell script \"" NFD_START_COMMAND "\" with administrator privileges");
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700251#endif
taylorchuc27dd482014-05-17 20:06:49 -0700252}
253
254void
255TrayMenu::stopNfd()
256{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700257#ifdef OSX_BUILD
258 QProcess* proc = new QProcess();
259 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
260 proc->startDetached("killall", QStringList() << "nfd");
261#endif
taylorchuc27dd482014-05-17 20:06:49 -0700262}
263
susmit4fe3cb92016-03-20 17:08:41 -0700264Q_INVOKABLE void
265TrayMenu::addDeleteRoute()
266{
267 addRoute();
268}
269
270Q_INVOKABLE void
271TrayMenu::addRoute()
272{
273 std::cout << "Adding route" << std::endl;
274 QString cmd = "nfdc register /test tcp4://localhost";
275 QProcess *addNewRoute = new QProcess();
276 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
277 addNewRoute->start("bash", QStringList() << "-c" << cmd);
278 std::cout << "Done" << std::endl;
susmit4fe3cb92016-03-20 17:08:41 -0700279}
280
281void
282TrayMenu::deleteRoute()
283{
284 std::cout << "Deleting route" << std::endl;
285 QString cmd = "nfdc unregister /test tcp4://localhost";
286 QProcess *addNewRoute = new QProcess();
287 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
288 addNewRoute->start("bash", QStringList() << "-c" << cmd);
289 std::cout << "Done" << std::endl;
susmit4fe3cb92016-03-20 17:08:41 -0700290}
291
taylorchuc27dd482014-05-17 20:06:49 -0700292void
293TrayMenu::updateNfdActivityIcon(bool isActive)
294{
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700295 m_isNfdRunning = isActive;
296
taylorchuc27dd482014-05-17 20:06:49 -0700297 if (isActive) {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700298 m_tray->setIcon(QIcon(CONNECT_ICON));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700299 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Stop NFD")));
taylorchuc27dd482014-05-17 20:06:49 -0700300 }
301 else {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700302 m_tray->setIcon(QIcon(DISCONNECT_ICON));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700303 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Start NFD")));
taylorchuc27dd482014-05-17 20:06:49 -0700304 }
305}
306
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700307void
308TrayMenu::enableCli()
309{
310#ifdef OSX_BUILD
311 AuthorizationRef authorizationRef;
312 OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
313 kAuthorizationFlagDefaults, &authorizationRef);
314 if (status != errAuthorizationSuccess)
315 return;
316
317 AuthorizationItem item = { kAuthorizationRightExecute, 0, 0, 0 };
318 AuthorizationRights rights = { 1, &item };
319 const AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed
320 | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
321
322 status = AuthorizationCopyRights(authorizationRef, &rights, kAuthorizationEmptyEnvironment,
323 flags, 0);
324 if (status != errAuthorizationSuccess)
325 return;
326
327 char const* mkdir_arg[] = { "-p", "/usr/local/bin", nullptr };
328 char const* mkdir = "/bin/mkdir";
329 AuthorizationExecuteWithPrivileges(authorizationRef,
330 mkdir,
331 kAuthorizationFlagDefaults, (char**)mkdir_arg, nullptr);
332
Alexander Afanasyev964feb92016-03-22 13:03:11 -0700333 std::vector<std::string> arguments = { "-f", "-s",
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700334 QCoreApplication::applicationDirPath().toStdString() + "/../Resources/ndn",
335 "/usr/local/bin/ndn" };
336 std::vector<const char*> args;
337 for (const auto& i : arguments) {
338 args.push_back(i.c_str());
339 }
340 args.push_back(nullptr);
341
Qi Zhao0e043e52016-12-05 18:27:09 -0800342 char const* helperTool = "/bin/ln";
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700343 AuthorizationExecuteWithPrivileges(authorizationRef,
344 helperTool,
345 kAuthorizationFlagDefaults,
346 (char**)args.data(), NULL);
347
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700348 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
349#endif
350}
351
Alexander Afanasyevfda42a82017-02-01 18:03:39 -0800352#ifdef OSX_BUILD
353void
354TrayMenu::checkForUpdates()
355{
356 m_sparkle.checkForUpdates();
357}
358#endif // OSX_BUILD
359
360} // namespace ncc
taylorchuc27dd482014-05-17 20:06:49 -0700361} // namespace ndn